early-access version 1509

This commit is contained in:
pineappleEA
2021-03-08 07:51:31 +01:00
parent cf27b36f44
commit c3f9e4a27b
3170 changed files with 9341219 additions and 163 deletions

View File

@@ -112,7 +112,9 @@ if ("A32" IN_LIST DYNARMIC_FRONTENDS)
frontend/A32/decoder/asimd.h
frontend/A32/decoder/asimd.inc
frontend/A32/decoder/thumb16.h
frontend/A32/decoder/thumb16.inc
frontend/A32/decoder/thumb32.h
frontend/A32/decoder/thumb32.inc
frontend/A32/decoder/vfp.h
frontend/A32/decoder/vfp.inc
frontend/A32/disassembler/disassembler.h
@@ -155,12 +157,18 @@ if ("A32" IN_LIST DYNARMIC_FRONTENDS)
frontend/A32/translate/impl/thumb16.cpp
frontend/A32/translate/impl/thumb32_branch.cpp
frontend/A32/translate/impl/thumb32_control.cpp
frontend/A32/translate/impl/thumb32_data_processing_register.cpp
frontend/A32/translate/impl/thumb32_data_processing_modified_immediate.cpp
frontend/A32/translate/impl/thumb32_data_processing_plain_binary_immediate.cpp
frontend/A32/translate/impl/thumb32_data_processing_register.cpp
frontend/A32/translate/impl/thumb32_data_processing_shifted_register.cpp
frontend/A32/translate/impl/thumb32_load_byte.cpp
frontend/A32/translate/impl/thumb32_load_halfword.cpp
frontend/A32/translate/impl/thumb32_load_word.cpp
frontend/A32/translate/impl/thumb32_long_multiply.cpp
frontend/A32/translate/impl/thumb32_misc.cpp
frontend/A32/translate/impl/thumb32_multiply.cpp
frontend/A32/translate/impl/thumb32_parallel.cpp
frontend/A32/translate/impl/thumb32_store_single_data_item.cpp
frontend/A32/translate/impl/translate_arm.h
frontend/A32/translate/impl/translate_thumb.h
frontend/A32/translate/impl/vfp.cpp
@@ -248,7 +256,7 @@ if ("A64" IN_LIST DYNARMIC_FRONTENDS)
)
endif()
if (ARCHITECTURE_x86_64)
if (ARCHITECTURE STREQUAL "x86_64")
target_sources(dynarmic PRIVATE
backend/x64/abi.cpp
backend/x64/abi.h

View File

@@ -989,7 +989,7 @@ void EmitFPVectorMulAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
};
if constexpr (fsize != 16) {
if (code.HasFMA() && code.HasAVX() && ctx.HasOptimization(OptimizationFlag::Unsafe_UnfuseFMA)) {
if (code.HasFMA() && code.HasAVX() && ctx.HasOptimization(OptimizationFlag::Unsafe_InaccurateNaN)) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
const bool fpcr_controlled = args[3].GetImmediateU1();

View File

@@ -29,28 +29,23 @@
//INST(thumb32_LDREXD, "LDREXD", "111010001101------------0111----")
// Data Processing (Shifted Register)
//INST(thumb32_TST_reg, "TST (reg)", "111010100001--------1111--------")
//INST(thumb32_AND_reg, "AND (reg)", "11101010000---------------------")
//INST(thumb32_BIC_reg, "BIC (reg)", "11101010001---------------------")
//INST(thumb32_MOV_reg, "MOV (reg)", "11101010010-1111-000----0000----")
//INST(thumb32_LSL_imm, "LSL (imm)", "11101010010-1111----------00----")
//INST(thumb32_LSR_imm, "LSR (imm)", "11101010010-1111----------01----")
//INST(thumb32_ASR_imm, "ASR (imm)", "11101010010-1111----------10----")
//INST(thumb32_RRX, "RRX", "11101010010-1111-000----0011----")
//INST(thumb32_ROR_imm, "ROR (imm)", "11101010010-1111----------11----")
//INST(thumb32_ORR_reg, "ORR (reg)", "11101010010---------------------")
//INST(thumb32_MVN_reg, "MVN (reg)", "11101010011-1111----------------")
//INST(thumb32_ORN_reg, "ORN (reg)", "11101010011---------------------")
//INST(thumb32_TEQ_reg, "TEQ (reg)", "111010101001--------1111--------")
//INST(thumb32_EOR_reg, "EOR (reg)", "11101010100---------------------")
//INST(thumb32_PKH, "PKH", "11101010110---------------------")
//INST(thumb32_CMN_reg, "CMN (reg)", "111010110001--------1111--------")
//INST(thumb32_ADD_reg, "ADD (reg)", "11101011000---------------------")
//INST(thumb32_ADC_reg, "ADC (reg)", "11101011010---------------------")
//INST(thumb32_SBC_reg, "SBC (reg)", "11101011011---------------------")
//INST(thumb32_CMP_reg, "CMP (reg)", "111010111011--------1111--------")
//INST(thumb32_SUB_reg, "SUB (reg)", "11101011101---------------------")
//INST(thumb32_RSB_reg, "RSB (reg)", "11101011110---------------------")
INST(thumb32_TST_reg, "TST (reg)", "111010100001nnnn0vvv1111vvttmmmm")
INST(thumb32_AND_reg, "AND (reg)", "11101010000Snnnn0vvvddddvvttmmmm")
INST(thumb32_BIC_reg, "BIC (reg)", "11101010001Snnnn0vvvddddvvttmmmm")
INST(thumb32_MOV_reg, "MOV (reg)", "11101010010S11110vvvddddvvttmmmm")
INST(thumb32_ORR_reg, "ORR (reg)", "11101010010Snnnn0vvvddddvvttmmmm")
INST(thumb32_MVN_reg, "MVN (reg)", "11101010011S11110vvvddddvvttmmmm")
INST(thumb32_ORN_reg, "ORN (reg)", "11101010011Snnnn0vvvddddvvttmmmm")
INST(thumb32_TEQ_reg, "TEQ (reg)", "111010101001nnnn0vvv1111vvttmmmm")
INST(thumb32_EOR_reg, "EOR (reg)", "11101010100Snnnn0vvvddddvvttmmmm")
INST(thumb32_PKH, "PKH", "111010101100nnnn0vvvddddvvt0mmmm")
INST(thumb32_CMN_reg, "CMN (reg)", "111010110001nnnn0vvv1111vvttmmmm")
INST(thumb32_ADD_reg, "ADD (reg)", "11101011000Snnnn0vvvddddvvttmmmm")
INST(thumb32_ADC_reg, "ADC (reg)", "11101011010Snnnn0vvvddddvvttmmmm")
INST(thumb32_SBC_reg, "SBC (reg)", "11101011011Snnnn0vvvddddvvttmmmm")
INST(thumb32_CMP_reg, "CMP (reg)", "111010111011nnnn0vvv1111vvttmmmm")
INST(thumb32_SUB_reg, "SUB (reg)", "11101011101Snnnn0vvvddddvvttmmmm")
INST(thumb32_RSB_reg, "RSB (reg)", "11101011110Snnnn0vvvddddvvttmmmm")
// Data Processing (Modified Immediate)
INST(thumb32_TST_imm, "TST (imm)", "11110v000001nnnn0vvv1111vvvvvvvv")
@@ -58,35 +53,34 @@ INST(thumb32_AND_imm, "AND (imm)", "11110v00000Snnnn0vvvdd
INST(thumb32_BIC_imm, "BIC (imm)", "11110v00001Snnnn0vvvddddvvvvvvvv")
INST(thumb32_MOV_imm, "MOV (imm)", "11110v00010S11110vvvddddvvvvvvvv")
INST(thumb32_ORR_imm, "ORR (imm)", "11110v00010Snnnn0vvvddddvvvvvvvv")
//INST(thumb32_MVN_imm, "MVN (imm)", "11110000011-11110---------------")
//INST(thumb32_ORN_imm, "ORN (imm)", "11110-00011-----0---------------")
//INST(thumb32_TEQ_imm, "TEQ (imm)", "11110-001001----0---1111--------")
//INST(thumb32_EOR_imm, "EOR (imm)", "11110-00100-----0---------------")
//INST(thumb32_CMN_imm, "CMN (imm)", "11110-010001----0---1111--------")
//INST(thumb32_ADD_imm_1, "ADD (imm)", "11110-01000-----0---------------")
//INST(thumb32_ADC_imm, "ADC (imm)", "11110-01010-----0---------------")
//INST(thumb32_SBC_imm, "SBC (imm)", "11110-01011-----0---------------")
//INST(thumb32_CMP_imm, "CMP (imm)", "11110-011011----0---1111--------")
//INST(thumb32_SUB_imm_1, "SUB (imm)", "11110-01101-----0---------------")
//INST(thumb32_RSB_imm, "RSB (imm)", "11110-01110-----0---------------")
INST(thumb32_MVN_imm, "MVN (imm)", "11110v00011S11110vvvddddvvvvvvvv")
INST(thumb32_ORN_imm, "ORN (imm)", "11110v00011Snnnn0vvvddddvvvvvvvv")
INST(thumb32_TEQ_imm, "TEQ (imm)", "11110v001001nnnn0vvv1111vvvvvvvv")
INST(thumb32_EOR_imm, "EOR (imm)", "11110v00100Snnnn0vvvddddvvvvvvvv")
INST(thumb32_CMN_imm, "CMN (imm)", "11110v010001nnnn0vvv1111vvvvvvvv")
INST(thumb32_ADD_imm_1, "ADD (imm)", "11110v01000Snnnn0vvvddddvvvvvvvv")
INST(thumb32_ADC_imm, "ADC (imm)", "11110v01010Snnnn0vvvddddvvvvvvvv")
INST(thumb32_SBC_imm, "SBC (imm)", "11110v01011Snnnn0vvvddddvvvvvvvv")
INST(thumb32_CMP_imm, "CMP (imm)", "11110v011011nnnn0vvv1111vvvvvvvv")
INST(thumb32_SUB_imm_1, "SUB (imm)", "11110v01101Snnnn0vvvddddvvvvvvvv")
INST(thumb32_RSB_imm, "RSB (imm)", "11110v01110Snnnn0vvvddddvvvvvvvv")
// Data Processing (Plain Binary Immediate)
//INST(thumb32_ADR, "ADR", "11110-10000011110---------------")
//INST(thumb32_ADD_imm_2, "ADD (imm)", "11110-100000----0---------------")
//INST(thumb32_MOVW_imm, "MOVW (imm)", "11110-100100----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_MOVT, "MOVT", "11110-101100----0---------------")
//INST(thumb32_SSAT, "SSAT", "11110-110000----0---------------")
//INST(thumb32_SSAT16, "SSAT16", "11110-110010----0000----00------")
//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_USAT, "USAT", "11110-111010----0---------------")
//INST(thumb32_UBFX, "UBFX", "11110-111100----0---------------")
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")
INST(thumb32_USAT, "USAT", "1111001110s0nnnn0iiiddddii0bbbbb")
INST(thumb32_SBFX, "SBFX", "111100110100nnnn0iiiddddii0wwwww")
INST(thumb32_BFC, "BFC", "11110011011011110iiiddddii0bbbbb")
INST(thumb32_BFI, "BFI", "111100110110nnnn0iiiddddii0bbbbb")
INST(thumb32_UBFX, "UBFX", "111100111100nnnn0iiiddddii0wwwww")
// Branches and Miscellaneous Control
//INST(thumb32_MSR_banked, "MSR (banked)", "11110011100-----10-0------1-----")
@@ -95,23 +89,23 @@ INST(thumb32_ORR_imm, "ORR (imm)", "11110v00010Snnnn0vvvdd
//INST(thumb32_MSR_reg_3, "MSR (reg)", "111100111000----10-0--1---0-----")
//INST(thumb32_MSR_reg_4, "MSR (reg)", "111100111000----10-0--00--0-----")
//INST(thumb32_NOP, "NOP", "111100111010----10-0-00000000000")
//INST(thumb32_YIELD, "YIELD", "111100111010----10-0-00000000001")
//INST(thumb32_WFE, "WFE", "111100111010----10-0-00000000010")
//INST(thumb32_WFI, "WFI", "111100111010----10-0-00000000011")
//INST(thumb32_SEV, "SEV", "111100111010----10-0-00000000100")
//INST(thumb32_SEVL, "SEVL", "111100111010----10-0-00000000101")
INST(thumb32_NOP, "NOP", "11110011101011111000000000000000")
INST(thumb32_YIELD, "YIELD", "11110011101011111000000000000001")
INST(thumb32_WFE, "WFE", "11110011101011111000000000000010")
INST(thumb32_WFI, "WFI", "11110011101011111000000000000011")
INST(thumb32_SEV, "SEV", "11110011101011111000000000000100")
INST(thumb32_SEVL, "SEVL", "11110011101011111000000000000101")
//INST(thumb32_DBG, "DBG", "111100111010----10-0-0001111----")
//INST(thumb32_CPS, "CPS", "111100111010----10-0------------")
//INST(thumb32_ENTERX, "ENTERX", "111100111011----10-0----0001----")
//INST(thumb32_LEAVEX, "LEAVEX", "111100111011----10-0----0000----")
//INST(thumb32_CLREX, "CLREX", "111100111011----10-0----0010----")
//INST(thumb32_DSB, "DSB", "111100111011----10-0----0100----")
//INST(thumb32_DMB, "DMB", "111100111011----10-0----0101----")
//INST(thumb32_ISB, "ISB", "111100111011----10-0----0110----")
INST(thumb32_CLREX, "CLREX", "11110011101111111000111100101111")
INST(thumb32_DSB, "DSB", "1111001110111111100011110100oooo")
INST(thumb32_DMB, "DMB", "1111001110111111100011110101oooo")
INST(thumb32_ISB, "ISB", "1111001110111111100011110110oooo")
//INST(thumb32_BXJ, "BXJ", "111100111100----1000111100000000")
INST(thumb32_BXJ, "BXJ", "111100111100mmmm1000111100000000")
//INST(thumb32_ERET, "ERET", "11110011110111101000111100000000")
//INST(thumb32_SUBS_pc_lr, "SUBS PC, LR", "111100111101111010001111--------")
@@ -125,45 +119,46 @@ INST(thumb32_UDF, "UDF", "111101111111----1010--
// Branch instructions
INST(thumb32_BL_imm, "BL (imm)", "11110Svvvvvvvvvv11j1jvvvvvvvvvvv") // v4T
INST(thumb32_BLX_imm, "BLX (imm)", "11110Svvvvvvvvvv11j0jvvvvvvvvvvv") // v5T
//INST(thumb32_B, "B", "11110-----------10-1------------")
//INST(thumb32_B_cond, "B (cond)", "11110-----------10-0------------")
INST(thumb32_B, "B", "11110Svvvvvvvvvv10j1jvvvvvvvvvvv")
INST(thumb32_UDF, "Invalid decoding", "11110-111-------10-0------------")
INST(thumb32_B_cond, "B (cond)", "11110Sccccvvvvvv10i0ivvvvvvvvvvv")
// Store Single Data Item
//INST(thumb32_STRB_imm_1, "STRB (imm)", "111110000000--------1--1--------")
//INST(thumb32_STRB_imm_2, "STRB (imm)", "111110000000--------1100--------")
//INST(thumb32_STRB_imm_3, "STRB (imm)", "111110001000--------------------")
//INST(thumb32_STRBT, "STRBT", "111110000000--------1110--------")
//INST(thumb32_STRB, "STRB (reg)", "111110000000--------000000------")
INST(thumb32_STRB, "STRB (reg)", "111110000000nnnntttt000000iimmmm")
//INST(thumb32_STRH_imm_1, "STRH (imm)", "111110000010--------1--1--------")
//INST(thumb32_STRH_imm_2, "STRH (imm)", "111110000010--------1100--------")
//INST(thumb32_STRH_imm_3, "STRH (imm)", "111110001010--------------------")
//INST(thumb32_STRHT, "STRHT", "111110000010--------1110--------")
//INST(thumb32_STRH, "STRH (reg)", "111110000010--------000000------")
INST(thumb32_STRH, "STRH (reg)", "111110000010nnnntttt000000iimmmm")
//INST(thumb32_STR_imm_1, "STR (imm)", "111110000100--------1--1--------")
//INST(thumb32_STR_imm_2, "STR (imm)", "111110000100--------1100--------")
//INST(thumb32_STR_imm_3, "STR (imm)", "111110001100--------------------")
//INST(thumb32_STRT, "STRT", "111110000100--------1110--------")
//INST(thumb32_STR_reg, "STR (reg)", "111110000100--------000000------")
INST(thumb32_STR_reg, "STR (reg)", "111110000100nnnntttt000000iimmmm")
// Load Byte and Memory Hints
//INST(thumb32_PLD_lit, "PLD (lit)", "11111000-00111111111------------")
//INST(thumb32_PLD_reg, "PLD (reg)", "111110000001----1111000000------")
//INST(thumb32_PLD_imm8, "PLD (imm8)", "1111100000-1----11111100--------")
//INST(thumb32_PLD_imm12, "PLD (imm12)", "111110001001----1111------------")
//INST(thumb32_PLI_lit, "PLI (lit)", "11111001-00111111111------------")
//INST(thumb32_PLI_reg, "PLI (reg)", "111110010001----1111000000------")
//INST(thumb32_PLI_imm8, "PLI (imm8)", "111110010001----11111100--------")
//INST(thumb32_PLI_imm12, "PLI (imm12)", "111110011001----1111------------")
//INST(thumb32_LDRB_lit, "LDRB (lit)", "11111000-0011111----------------")
//INST(thumb32_LDRB_reg, "LDRB (reg)", "111110000001--------000000------")
//INST(thumb32_LDRBT, "LDRBT", "111110000001--------1110--------")
//INST(thumb32_LDRB_imm8, "LDRB (imm8)", "111110000001--------1-----------")
//INST(thumb32_LDRB_imm12, "LDRB (imm12)", "111110001001--------------------")
//INST(thumb32_LDRSB_lit, "LDRSB (lit)", "11111001-0011111----------------")
//INST(thumb32_LDRSB_reg, "LDRSB (reg)", "111110010001--------000000------")
//INST(thumb32_LDRSBT, "LDRSBT", "111110010001--------1110--------")
//INST(thumb32_LDRSB_imm8, "LDRSB (imm8)", "111110010001--------1-----------")
//INST(thumb32_LDRSB_imm12, "LDRSB (imm12)", "111110011001--------------------")
INST(thumb32_PLD_lit, "PLD (lit)", "11111000U00111111111iiiiiiiiiiii")
INST(thumb32_PLD_reg, "PLD (reg)", "1111100000W1nnnn1111000000iimmmm")
INST(thumb32_PLD_imm8, "PLD (imm8)", "1111100000W1nnnn11111100iiiiiiii")
INST(thumb32_PLD_imm12, "PLD (imm12)", "1111100010W1nnnn1111iiiiiiiiiiii")
INST(thumb32_PLI_lit, "PLI (lit)", "11111001U00111111111iiiiiiiiiiii")
INST(thumb32_PLI_reg, "PLI (reg)", "111110010001nnnn1111000000iimmmm")
INST(thumb32_PLI_imm8, "PLI (imm8)", "111110010001nnnn11111100iiiiiiii")
INST(thumb32_PLI_imm12, "PLI (imm12)", "111110011001nnnn1111iiiiiiiiiiii")
INST(thumb32_LDRB_lit, "LDRB (lit)", "11111000U0011111ttttiiiiiiiiiiii")
INST(thumb32_LDRB_reg, "LDRB (reg)", "111110000001nnnntttt000000iimmmm")
INST(thumb32_LDRBT, "LDRBT", "111110000001nnnntttt1110iiiiiiii")
INST(thumb32_LDRB_imm8, "LDRB (imm8)", "111110000001nnnntttt1PUWiiiiiiii")
INST(thumb32_LDRB_imm12, "LDRB (imm12)", "111110001001nnnnttttiiiiiiiiiiii")
INST(thumb32_LDRSB_lit, "LDRSB (lit)", "11111001U0011111ttttiiiiiiiiiiii")
INST(thumb32_LDRSB_reg, "LDRSB (reg)", "111110010001nnnntttt000000iimmmm")
INST(thumb32_LDRSBT, "LDRSBT", "111110010001nnnntttt1110iiiiiiii")
INST(thumb32_LDRSB_imm8, "LDRSB (imm8)", "111110010001nnnntttt1PUWiiiiiiii")
INST(thumb32_LDRSB_imm12, "LDRSB (imm12)", "111110011001nnnnttttiiiiiiiiiiii")
// Load Halfword and Memory Hints
//INST(thumb32_LDRH_lit, "LDRH (lit)", "11111000-0111111----------------")
@@ -189,10 +184,10 @@ INST(thumb32_BLX_imm, "BLX (imm)", "11110Svvvvvvvvvv11j0jv
//INST(thumb32_LDR_imm12, "LDR (imm12)", "111110001101--------------------")
// Data Processing (register)
//INST(thumb32_LSL_reg, "LSL (reg)", "11111010000-----1111----0000----")
//INST(thumb32_LSR_reg, "LSR (reg)", "11111010001-----1111----0000----")
//INST(thumb32_ASR_reg, "ASR (reg)", "11111010010-----1111----0000----")
//INST(thumb32_ROR_reg, "ROR (reg)", "11111010011-----1111----0000----")
INST(thumb32_LSL_reg, "LSL (reg)", "111110100000mmmm1111dddd0000ssss")
INST(thumb32_LSR_reg, "LSR (reg)", "111110100010mmmm1111dddd0000ssss")
INST(thumb32_ASR_reg, "ASR (reg)", "111110100100mmmm1111dddd0000ssss")
INST(thumb32_ROR_reg, "ROR (reg)", "111110100110mmmm1111dddd0000ssss")
INST(thumb32_SXTH, "SXTH", "11111010000011111111dddd10rrmmmm")
INST(thumb32_SXTAH, "SXTAH", "111110100000nnnn1111dddd10rrmmmm")
INST(thumb32_UXTH, "UXTH", "11111010000111111111dddd10rrmmmm")

View File

@@ -860,7 +860,7 @@ bool ThumbTranslatorVisitor::thumb16_SETEND(bool E) {
return true;
}
ir.SetTerm(IR::Term::LinkBlock{ir.current_location.AdvancePC(2).SetEFlag(E)});
ir.SetTerm(IR::Term::LinkBlock{ir.current_location.AdvancePC(2).SetEFlag(E).AdvanceIT()});
return false;
}
@@ -967,8 +967,8 @@ bool ThumbTranslatorVisitor::thumb16_CBZ_CBNZ(bool nonzero, Imm<1> i, Imm<5> imm
ir.SetCheckBit(ir.IsZero(rn));
const auto [cond_pass, cond_fail] = [this, imm, nonzero] {
const auto skip = IR::Term::LinkBlock{ir.current_location.AdvancePC(2)};
const auto branch = IR::Term::LinkBlock{ir.current_location.AdvancePC(imm + 4)};
const auto skip = IR::Term::LinkBlock{ir.current_location.AdvancePC(2).AdvanceIT()};
const auto branch = IR::Term::LinkBlock{ir.current_location.AdvancePC(imm + 4).AdvanceIT()};
if (nonzero) {
return std::make_pair(skip, branch);

View File

@@ -52,4 +52,37 @@ bool ThumbTranslatorVisitor::thumb32_BLX_imm(Imm<1> S, Imm<10> hi, Imm<1> j1, Im
return false;
}
bool ThumbTranslatorVisitor::thumb32_B(Imm<1> S, Imm<10> hi, Imm<1> j1, Imm<1> j2, Imm<11> lo) {
const Imm<1> i1{j1 == S};
const Imm<1> i2{j2 == S};
if (ir.current_location.IT().IsInITBlock() && !ir.current_location.IT().IsLastInITBlock()) {
return UnpredictableInstruction();
}
const s32 imm32 = static_cast<s32>((concatenate(S, i1, i2, hi, lo).SignExtend<u32>() << 1) + 4);
const auto new_location = ir.current_location
.AdvancePC(imm32)
.AdvanceIT();
ir.SetTerm(IR::Term::LinkBlock{new_location});
return false;
}
bool ThumbTranslatorVisitor::thumb32_B_cond(Imm<1> S, Cond cond, Imm<6> hi, Imm<1> i1, Imm<1> i2, Imm<11> lo) {
if (ir.current_location.IT().IsInITBlock()) {
return UnpredictableInstruction();
}
// Note: i1 and i2 were not inverted from encoding and are opposite compared to the other B instructions.
const s32 imm32 = static_cast<s32>((concatenate(S, i2, i1, hi, lo).SignExtend<u32>() << 1) + 4);
const auto then_location = ir.current_location
.AdvancePC(imm32)
.AdvanceIT();
const auto else_location = ir.current_location
.AdvancePC(4)
.AdvanceIT();
ir.SetTerm(IR::Term::If{cond, IR::Term::LinkBlock{then_location}, IR::Term::LinkBlock{else_location}});
return false;
}
} // namespace Dynarmic::A32

View File

@@ -7,8 +7,63 @@
namespace Dynarmic::A32 {
bool ThumbTranslatorVisitor::thumb32_BXJ(Reg m) {
if (m == Reg::PC) {
return UnpredictableInstruction();
}
return thumb16_BX(m);
}
bool ThumbTranslatorVisitor::thumb32_CLREX() {
ir.ClearExclusive();
return true;
}
bool ThumbTranslatorVisitor::thumb32_DMB([[maybe_unused]] Imm<4> option) {
ir.DataMemoryBarrier();
return true;
}
bool ThumbTranslatorVisitor::thumb32_DSB([[maybe_unused]] Imm<4> option) {
ir.DataSynchronizationBarrier();
return true;
}
bool ThumbTranslatorVisitor::thumb32_ISB([[maybe_unused]] Imm<4> option) {
ir.InstructionSynchronizationBarrier();
ir.UpdateUpperLocationDescriptor();
ir.BranchWritePC(ir.Imm32(ir.current_location.PC() + 4));
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
bool ThumbTranslatorVisitor::thumb32_NOP() {
return thumb16_NOP();
}
bool ThumbTranslatorVisitor::thumb32_SEV() {
return thumb16_SEV();
}
bool ThumbTranslatorVisitor::thumb32_SEVL() {
return thumb16_SEVL();
}
bool ThumbTranslatorVisitor::thumb32_UDF() {
return thumb16_UDF();
}
bool ThumbTranslatorVisitor::thumb32_WFE() {
return thumb16_WFE();
}
bool ThumbTranslatorVisitor::thumb32_WFI() {
return thumb16_WFI();
}
bool ThumbTranslatorVisitor::thumb32_YIELD() {
return thumb16_YIELD();
}
} // namespace Dynarmic::A32

View File

@@ -91,4 +91,193 @@ bool ThumbTranslatorVisitor::thumb32_ORR_imm(Imm<1> i, bool S, Reg n, Imm<3> imm
return true;
}
bool ThumbTranslatorVisitor::thumb32_MVN_imm(Imm<1> i, bool S, Imm<3> imm3, Reg d, Imm<8> imm8) {
if (d == Reg::PC) {
return UnpredictableInstruction();
}
const auto imm_carry = ThumbExpandImm_C(i, imm3, imm8, ir.GetCFlag());
const auto result = ir.Imm32(~imm_carry.imm32);
ir.SetRegister(d, result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result));
ir.SetZFlag(ir.IsZero(result));
ir.SetCFlag(imm_carry.carry);
}
return true;
}
bool ThumbTranslatorVisitor::thumb32_ORN_imm(Imm<1> i, bool S, Reg n, Imm<3> imm3, Reg d, Imm<8> imm8) {
ASSERT_MSG(n != Reg::PC, "Decode error");
if (d == Reg::PC) {
return UnpredictableInstruction();
}
const auto imm_carry = ThumbExpandImm_C(i, imm3, imm8, ir.GetCFlag());
const auto result = ir.Or(ir.GetRegister(n), ir.Imm32(~imm_carry.imm32));
ir.SetRegister(d, result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result));
ir.SetZFlag(ir.IsZero(result));
ir.SetCFlag(imm_carry.carry);
}
return true;
}
bool ThumbTranslatorVisitor::thumb32_TEQ_imm(Imm<1> i, Reg n, Imm<3> imm3, Imm<8> imm8) {
if (n == Reg::PC) {
return UnpredictableInstruction();
}
const auto imm_carry = ThumbExpandImm_C(i, imm3, imm8, ir.GetCFlag());
const auto result = ir.Eor(ir.GetRegister(n), ir.Imm32(imm_carry.imm32));
ir.SetNFlag(ir.MostSignificantBit(result));
ir.SetZFlag(ir.IsZero(result));
ir.SetCFlag(imm_carry.carry);
return true;
}
bool ThumbTranslatorVisitor::thumb32_EOR_imm(Imm<1> i, bool S, Reg n, Imm<3> imm3, Reg d, Imm<8> imm8) {
ASSERT_MSG(!(d == Reg::PC && S), "Decode error");
if ((d == Reg::PC && !S) || n == Reg::PC) {
return UnpredictableInstruction();
}
const auto imm_carry = ThumbExpandImm_C(i, imm3, imm8, ir.GetCFlag());
const auto result = ir.Eor(ir.GetRegister(n), ir.Imm32(imm_carry.imm32));
ir.SetRegister(d, result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result));
ir.SetZFlag(ir.IsZero(result));
ir.SetCFlag(imm_carry.carry);
}
return true;
}
bool ThumbTranslatorVisitor::thumb32_CMN_imm(Imm<1> i, Reg n, Imm<3> imm3, Imm<8> imm8) {
if (n == Reg::PC) {
return UnpredictableInstruction();
}
const auto imm32 = ThumbExpandImm(i, imm3, imm8);
const auto result = ir.AddWithCarry(ir.GetRegister(n), ir.Imm32(imm32), 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;
}
bool ThumbTranslatorVisitor::thumb32_ADD_imm_1(Imm<1> i, bool S, Reg n, Imm<3> imm3, Reg d, Imm<8> imm8) {
ASSERT_MSG(!(d == Reg::PC && S), "Decode error");
if ((d == Reg::PC && !S) || n == Reg::PC) {
return UnpredictableInstruction();
}
const auto imm32 = ThumbExpandImm(i, imm3, imm8);
const auto result = ir.AddWithCarry(ir.GetRegister(n), ir.Imm32(imm32), ir.Imm1(0));
ir.SetRegister(d, result.result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetZFlag(ir.IsZero(result.result));
ir.SetCFlag(result.carry);
ir.SetVFlag(result.overflow);
}
return true;
}
bool ThumbTranslatorVisitor::thumb32_ADC_imm(Imm<1> i, bool S, Reg n, Imm<3> imm3, Reg d, Imm<8> imm8) {
if (d == Reg::PC || n == Reg::PC) {
return UnpredictableInstruction();
}
const auto imm32 = ThumbExpandImm(i, imm3, imm8);
const auto result = ir.AddWithCarry(ir.GetRegister(n), ir.Imm32(imm32), ir.GetCFlag());
ir.SetRegister(d, result.result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetZFlag(ir.IsZero(result.result));
ir.SetCFlag(result.carry);
ir.SetVFlag(result.overflow);
}
return true;
}
bool ThumbTranslatorVisitor::thumb32_SBC_imm(Imm<1> i, bool S, Reg n, Imm<3> imm3, Reg d, Imm<8> imm8) {
if (d == Reg::PC || n == Reg::PC) {
return UnpredictableInstruction();
}
const auto imm32 = ThumbExpandImm(i, imm3, imm8);
const auto result = ir.SubWithCarry(ir.GetRegister(n), ir.Imm32(imm32), ir.GetCFlag());
ir.SetRegister(d, result.result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetZFlag(ir.IsZero(result.result));
ir.SetCFlag(result.carry);
ir.SetVFlag(result.overflow);
}
return true;
}
bool ThumbTranslatorVisitor::thumb32_CMP_imm(Imm<1> i, Reg n, Imm<3> imm3, Imm<8> imm8) {
if (n == Reg::PC) {
return UnpredictableInstruction();
}
const auto imm32 = ThumbExpandImm(i, imm3, imm8);
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;
}
bool ThumbTranslatorVisitor::thumb32_SUB_imm_1(Imm<1> i, bool S, Reg n, Imm<3> imm3, Reg d, Imm<8> imm8) {
ASSERT_MSG(!(d == Reg::PC && S), "Decode error");
if ((d == Reg::PC && !S) || n == Reg::PC) {
return UnpredictableInstruction();
}
const auto imm32 = ThumbExpandImm(i, imm3, imm8);
const auto result = ir.SubWithCarry(ir.GetRegister(n), ir.Imm32(imm32), ir.Imm1(1));
ir.SetRegister(d, result.result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetZFlag(ir.IsZero(result.result));
ir.SetCFlag(result.carry);
ir.SetVFlag(result.overflow);
}
return true;
}
bool ThumbTranslatorVisitor::thumb32_RSB_imm(Imm<1> i, bool S, Reg n, Imm<3> imm3, Reg d, Imm<8> imm8) {
if (d == Reg::PC || n == Reg::PC) {
return UnpredictableInstruction();
}
const auto imm32 = ThumbExpandImm(i, imm3, imm8);
const auto result = ir.SubWithCarry(ir.Imm32(imm32), ir.GetRegister(n), ir.Imm1(1));
ir.SetRegister(d, result.result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetZFlag(ir.IsZero(result.result));
ir.SetCFlag(result.carry);
ir.SetVFlag(result.overflow);
}
return true;
}
} // namespace Dynarmic::A32

View File

@@ -0,0 +1,207 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2021 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#include "common/assert.h"
#include "common/bit_util.h"
#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<IR::U32> (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();
}
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();
}
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_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();
}
const u32 lsbit = concatenate(imm3, imm2).ZeroExtend();
const u32 msbit = msb.ZeroExtend();
if (msbit < lsbit) {
return UnpredictableInstruction();
}
const u32 mask = ~(Common::Ones<u32>(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<u32>(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();
}
const IR::U32 imm16 = ir.Imm32(concatenate(imm4, imm1, imm3, imm8).ZeroExtend() << 16);
const IR::U32 operand = ir.GetRegister(d);
const IR::U32 result = ir.Or(ir.And(operand, ir.Imm32(0x0000FFFFU)), imm16);
ir.SetRegister(d, result);
return true;
}
bool ThumbTranslatorVisitor::thumb32_MOVW_imm(Imm<1> imm1, Imm<4> imm4, Imm<3> imm3, Reg d, Imm<8> imm8) {
if (d == Reg::PC) {
return UnpredictableInstruction();
}
const IR::U32 imm = ir.Imm32(concatenate(imm4, imm1, imm3, imm8).ZeroExtend());
ir.SetRegister(d, imm);
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<u32>()) {
return UnpredictableInstruction();
}
constexpr size_t max_width = Common::BitSize<u32>();
const auto width = widthm1_value + 1;
const auto left_shift_amount = static_cast<u8>(max_width - width - lsbit);
const auto right_shift_amount = static_cast<u8>(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_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);
}
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();
}
const u32 lsbit = concatenate(imm3, imm2).ZeroExtend();
const u32 widthm1_value = widthm1.ZeroExtend();
const u32 msb = lsbit + widthm1_value;
if (msb >= Common::BitSize<u32>()) {
return UnpredictableInstruction();
}
const auto operand = ir.GetRegister(n);
const auto mask = ir.Imm32(Common::Ones<u32>(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_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);
}
} // namespace Dynarmic::A32

View File

@@ -6,11 +6,44 @@
#include "frontend/A32/translate/impl/translate_thumb.h"
namespace Dynarmic::A32 {
static IR::U32 Rotate(A32::IREmitter& ir, Reg m, SignExtendRotation rotate) {
namespace {
IR::U32 Rotate(A32::IREmitter& ir, Reg m, SignExtendRotation rotate) {
const u8 rotate_by = static_cast<u8>(static_cast<size_t>(rotate) * 8);
return ir.RotateRight(ir.GetRegister(m), ir.Imm8(rotate_by), ir.Imm1(0)).result;
}
using ShiftFunction = IR::ResultAndCarry<IR::U32> (IREmitter::*)(const IR::U32&, const IR::U8&, const IR::U1&);
bool ShiftInstruction(ThumbTranslatorVisitor& v, Reg m, Reg d, Reg s, ShiftFunction shift_fn) {
if (d == Reg::PC || m == Reg::PC || s == Reg::PC) {
return v.UnpredictableInstruction();
}
const auto shift_s = v.ir.LeastSignificantByte(v.ir.GetRegister(s));
const auto apsr_c = v.ir.GetCFlag();
const auto result_carry = (v.ir.*shift_fn)(v.ir.GetRegister(m), shift_s, apsr_c);
v.ir.SetRegister(d, result_carry.result);
return true;
}
} // Anonymous namespace
bool ThumbTranslatorVisitor::thumb32_ASR_reg(Reg m, Reg d, Reg s) {
return ShiftInstruction(*this, m, d, s, &IREmitter::ArithmeticShiftRight);
}
bool ThumbTranslatorVisitor::thumb32_LSL_reg(Reg m, Reg d, Reg s) {
return ShiftInstruction(*this, m, d, s, &IREmitter::LogicalShiftLeft);
}
bool ThumbTranslatorVisitor::thumb32_LSR_reg(Reg m, Reg d, Reg s) {
return ShiftInstruction(*this, m, d, s, &IREmitter::LogicalShiftRight);
}
bool ThumbTranslatorVisitor::thumb32_ROR_reg(Reg m, Reg d, Reg s) {
return ShiftInstruction(*this, m, d, s, &IREmitter::RotateRight);
}
bool ThumbTranslatorVisitor::thumb32_SXTB(Reg d, SignExtendRotation rotate, Reg m) {
if (d == Reg::PC || m == Reg::PC) {
return UnpredictableInstruction();

View File

@@ -0,0 +1,292 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#include "frontend/A32/translate/impl/translate_thumb.h"
namespace Dynarmic::A32 {
bool ThumbTranslatorVisitor::thumb32_TST_reg(Reg n, Imm<3> imm3, Imm<2> imm2, ShiftType type, Reg m) {
if (n == Reg::PC || m == Reg::PC) {
return UnpredictableInstruction();
}
const auto shifted = EmitImmShift(ir.GetRegister(m), type, imm3, imm2, ir.GetCFlag());
const auto result = ir.And(ir.GetRegister(n), shifted.result);
ir.SetNFlag(ir.MostSignificantBit(result));
ir.SetZFlag(ir.IsZero(result));
ir.SetCFlag(shifted.carry);
return true;
}
bool ThumbTranslatorVisitor::thumb32_AND_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, ShiftType type, Reg m) {
ASSERT_MSG(!(d == Reg::PC && S), "Decode error");
if ((d == Reg::PC && !S) || n == Reg::PC || m == Reg::PC) {
return UnpredictableInstruction();
}
const auto shifted = EmitImmShift(ir.GetRegister(m), type, imm3, imm2, ir.GetCFlag());
const auto result = ir.And(ir.GetRegister(n), shifted.result);
ir.SetRegister(d, result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result));
ir.SetZFlag(ir.IsZero(result));
ir.SetCFlag(shifted.carry);
}
return true;
}
bool ThumbTranslatorVisitor::thumb32_BIC_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, ShiftType type, Reg m) {
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
return UnpredictableInstruction();
}
const auto shifted = EmitImmShift(ir.GetRegister(m), type, imm3, imm2, ir.GetCFlag());
const auto result = ir.And(ir.GetRegister(n), ir.Not(shifted.result));
ir.SetRegister(d, result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result));
ir.SetZFlag(ir.IsZero(result));
ir.SetCFlag(shifted.carry);
}
return true;
}
bool ThumbTranslatorVisitor::thumb32_MOV_reg(bool S, Imm<3> imm3, Reg d, Imm<2> imm2, ShiftType type, Reg m) {
if (d == Reg::PC || m == Reg::PC) {
return UnpredictableInstruction();
}
const auto shifted = EmitImmShift(ir.GetRegister(m), type, imm3, imm2, ir.GetCFlag());
const auto result = shifted.result;
ir.SetRegister(d, result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result));
ir.SetZFlag(ir.IsZero(result));
ir.SetCFlag(shifted.carry);
}
return true;
}
bool ThumbTranslatorVisitor::thumb32_ORR_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, ShiftType type, Reg m) {
ASSERT_MSG(n != Reg::PC, "Decode error");
if (d == Reg::PC || m == Reg::PC) {
return UnpredictableInstruction();
}
const auto shifted = EmitImmShift(ir.GetRegister(m), type, imm3, imm2, ir.GetCFlag());
const auto result = ir.Or(ir.GetRegister(n), shifted.result);
ir.SetRegister(d, result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result));
ir.SetZFlag(ir.IsZero(result));
ir.SetCFlag(shifted.carry);
}
return true;
}
bool ThumbTranslatorVisitor::thumb32_MVN_reg(bool S, Imm<3> imm3, Reg d, Imm<2> imm2, ShiftType type, Reg m) {
if (d == Reg::PC || m == Reg::PC) {
return UnpredictableInstruction();
}
const auto shifted = EmitImmShift(ir.GetRegister(m), type, imm3, imm2, ir.GetCFlag());
const auto result = ir.Not(shifted.result);
ir.SetRegister(d, result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result));
ir.SetZFlag(ir.IsZero(result));
ir.SetCFlag(shifted.carry);
}
return true;
}
bool ThumbTranslatorVisitor::thumb32_ORN_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, ShiftType type, Reg m) {
ASSERT_MSG(n != Reg::PC, "Decode error");
if (d == Reg::PC || m == Reg::PC) {
return UnpredictableInstruction();
}
const auto shifted = EmitImmShift(ir.GetRegister(m), type, imm3, imm2, ir.GetCFlag());
const auto result = ir.Or(ir.GetRegister(n), ir.Not(shifted.result));
ir.SetRegister(d, result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result));
ir.SetZFlag(ir.IsZero(result));
ir.SetCFlag(shifted.carry);
}
return true;
}
bool ThumbTranslatorVisitor::thumb32_TEQ_reg(Reg n, Imm<3> imm3, Imm<2> imm2, ShiftType type, Reg m) {
if (n == Reg::PC || m == Reg::PC) {
return UnpredictableInstruction();
}
const auto shifted = EmitImmShift(ir.GetRegister(m), type, imm3, imm2, ir.GetCFlag());
const auto result = ir.Eor(ir.GetRegister(n), shifted.result);
ir.SetNFlag(ir.MostSignificantBit(result));
ir.SetZFlag(ir.IsZero(result));
ir.SetCFlag(shifted.carry);
return true;
}
bool ThumbTranslatorVisitor::thumb32_EOR_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, ShiftType type, Reg m) {
ASSERT_MSG(!(d == Reg::PC && S), "Decode error");
if ((d == Reg::PC && !S) || n == Reg::PC || m == Reg::PC) {
return UnpredictableInstruction();
}
const auto shifted = EmitImmShift(ir.GetRegister(m), type, imm3, imm2, ir.GetCFlag());
const auto result = ir.Eor(ir.GetRegister(n), shifted.result);
ir.SetRegister(d, result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result));
ir.SetZFlag(ir.IsZero(result));
ir.SetCFlag(shifted.carry);
}
return true;
}
bool ThumbTranslatorVisitor::thumb32_PKH(Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, Imm<1> tb, Reg m) {
const ShiftType type = concatenate(tb, Imm<1>{0}).ZeroExtend<ShiftType>();
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
return UnpredictableInstruction();
}
const auto operand2 = EmitImmShift(ir.GetRegister(m), type, imm3, imm2, ir.GetCFlag()).result;
const auto lower = ir.And((tb == 1) ? operand2 : ir.GetRegister(n), ir.Imm32(0x0000FFFF));
const auto upper = ir.And((tb == 1) ? ir.GetRegister(n) : operand2, ir.Imm32(0xFFFF0000));
const auto result = ir.Or(upper, lower);
ir.SetRegister(d, result);
return true;
}
bool ThumbTranslatorVisitor::thumb32_CMN_reg(Reg n, Imm<3> imm3, Imm<2> imm2, ShiftType type, Reg m) {
if (n == Reg::PC || m == Reg::PC) {
return UnpredictableInstruction();
}
const auto shifted = EmitImmShift(ir.GetRegister(m), type, imm3, imm2, ir.GetCFlag());
const auto result = ir.AddWithCarry(ir.GetRegister(n), shifted.result, 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;
}
bool ThumbTranslatorVisitor::thumb32_ADD_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, ShiftType type, Reg m) {
ASSERT_MSG(!(d == Reg::PC && S), "Decode error");
if ((d == Reg::PC && !S) || n == Reg::PC || m == Reg::PC) {
return UnpredictableInstruction();
}
const auto shifted = EmitImmShift(ir.GetRegister(m), type, imm3, imm2, ir.GetCFlag());
const auto result = ir.AddWithCarry(ir.GetRegister(n), shifted.result, ir.Imm1(0));
ir.SetRegister(d, result.result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetZFlag(ir.IsZero(result.result));
ir.SetCFlag(result.carry);
ir.SetVFlag(result.overflow);
}
return true;
}
bool ThumbTranslatorVisitor::thumb32_ADC_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, ShiftType type, Reg m) {
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
return UnpredictableInstruction();
}
const auto shifted = EmitImmShift(ir.GetRegister(m), type, imm3, imm2, ir.GetCFlag());
const auto result = ir.AddWithCarry(ir.GetRegister(n), shifted.result, ir.GetCFlag());
ir.SetRegister(d, result.result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetZFlag(ir.IsZero(result.result));
ir.SetCFlag(result.carry);
ir.SetVFlag(result.overflow);
}
return true;
}
bool ThumbTranslatorVisitor::thumb32_SBC_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, ShiftType type, Reg m) {
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
return UnpredictableInstruction();
}
const auto shifted = EmitImmShift(ir.GetRegister(m), type, imm3, imm2, ir.GetCFlag());
const auto result = ir.SubWithCarry(ir.GetRegister(n), shifted.result, ir.GetCFlag());
ir.SetRegister(d, result.result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetZFlag(ir.IsZero(result.result));
ir.SetCFlag(result.carry);
ir.SetVFlag(result.overflow);
}
return true;
}
bool ThumbTranslatorVisitor::thumb32_CMP_reg(Reg n, Imm<3> imm3, Imm<2> imm2, ShiftType type, Reg m) {
if (n == Reg::PC || m == Reg::PC) {
return UnpredictableInstruction();
}
const auto shifted = EmitImmShift(ir.GetRegister(m), type, imm3, imm2, ir.GetCFlag());
const auto result = ir.SubWithCarry(ir.GetRegister(n), shifted.result, 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;
}
bool ThumbTranslatorVisitor::thumb32_SUB_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, ShiftType type, Reg m) {
ASSERT_MSG(!(d == Reg::PC && S), "Decode error");
if ((d == Reg::PC && !S) || n == Reg::PC || m == Reg::PC) {
return UnpredictableInstruction();
}
const auto shifted = EmitImmShift(ir.GetRegister(m), type, imm3, imm2, ir.GetCFlag());
const auto result = ir.SubWithCarry(ir.GetRegister(n), shifted.result, ir.Imm1(1));
ir.SetRegister(d, result.result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetZFlag(ir.IsZero(result.result));
ir.SetCFlag(result.carry);
ir.SetVFlag(result.overflow);
}
return true;
}
bool ThumbTranslatorVisitor::thumb32_RSB_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, ShiftType type, Reg m) {
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
return UnpredictableInstruction();
}
const auto shifted = EmitImmShift(ir.GetRegister(m), type, imm3, imm2, ir.GetCFlag());
const auto result = ir.SubWithCarry(shifted.result, ir.GetRegister(n), ir.Imm1(1));
ir.SetRegister(d, result.result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetZFlag(ir.IsZero(result.result));
ir.SetCFlag(result.carry);
ir.SetVFlag(result.overflow);
}
return true;
}
} // namespace Dynarmic::A32

View File

@@ -0,0 +1,210 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2021 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#include <dynarmic/A32/config.h>
#include "frontend/A32/translate/impl/translate_thumb.h"
namespace Dynarmic::A32 {
static bool PLDHandler(ThumbTranslatorVisitor& v, bool W) {
if (!v.options.hook_hint_instructions) {
return true;
}
const auto exception = W ? Exception::PreloadDataWithIntentToWrite
: Exception::PreloadData;
return v.RaiseException(exception);
}
static bool PLIHandler(ThumbTranslatorVisitor& v) {
if (!v.options.hook_hint_instructions) {
return true;
}
return v.RaiseException(Exception::PreloadInstruction);
}
using ExtensionFunction = IR::U32 (IREmitter::*)(const IR::U8&);
static bool LoadByteLiteral(ThumbTranslatorVisitor& v, bool U, Reg t, Imm<12> imm12,
ExtensionFunction ext_fn) {
const u32 imm32 = imm12.ZeroExtend();
const u32 base = v.ir.AlignPC(4);
const u32 address = U ? (base + imm32) : (base - imm32);
const auto data = (v.ir.*ext_fn)(v.ir.ReadMemory8(v.ir.Imm32(address)));
v.ir.SetRegister(t, data);
return true;
}
static bool LoadByteRegister(ThumbTranslatorVisitor& v, Reg n, Reg t, Imm<2> imm2, Reg m,
ExtensionFunction ext_fn) {
if (m == Reg::PC) {
return v.UnpredictableInstruction();
}
const auto reg_n = v.ir.GetRegister(n);
const auto reg_m = v.ir.GetRegister(m);
const auto offset = v.ir.LogicalShiftLeft(reg_m, v.ir.Imm8(imm2.ZeroExtend<u8>()));
const auto address = v.ir.Add(reg_n, offset);
const auto data = (v.ir.*ext_fn)(v.ir.ReadMemory8(address));
v.ir.SetRegister(t, data);
return true;
}
static bool LoadByteImmediate(ThumbTranslatorVisitor& v, Reg n, Reg t, bool P, bool U, bool W,
Imm<12> imm12, ExtensionFunction ext_fn) {
const u32 imm32 = imm12.ZeroExtend();
const IR::U32 reg_n = v.ir.GetRegister(n);
const IR::U32 offset_address = U ? v.ir.Add(reg_n, v.ir.Imm32(imm32))
: v.ir.Sub(reg_n, v.ir.Imm32(imm32));
const IR::U32 address = P ? offset_address : reg_n;
const IR::U32 data = (v.ir.*ext_fn)(v.ir.ReadMemory8(address));
v.ir.SetRegister(t, data);
if (W) {
v.ir.SetRegister(n, offset_address);
}
return true;
}
bool ThumbTranslatorVisitor::thumb32_PLD_lit([[maybe_unused]] bool U,
[[maybe_unused]] Imm<12> imm12) {
return PLDHandler(*this, false);
}
bool ThumbTranslatorVisitor::thumb32_PLD_imm8(bool W,
[[maybe_unused]] Reg n,
[[maybe_unused]] Imm<8> imm8) {
return PLDHandler(*this, W);
}
bool ThumbTranslatorVisitor::thumb32_PLD_imm12(bool W,
[[maybe_unused]] Reg n,
[[maybe_unused]] Imm<12> imm12) {
return PLDHandler(*this, W);
}
bool ThumbTranslatorVisitor::thumb32_PLD_reg(bool W,
[[maybe_unused]] Reg n,
[[maybe_unused]] Imm<2> imm2,
Reg m) {
if (m == Reg::PC) {
return UnpredictableInstruction();
}
return PLDHandler(*this, W);
}
bool ThumbTranslatorVisitor::thumb32_PLI_lit([[maybe_unused]] bool U,
[[maybe_unused]] Imm<12> imm12) {
return PLIHandler(*this);
}
bool ThumbTranslatorVisitor::thumb32_PLI_imm8([[maybe_unused]] Reg n,
[[maybe_unused]] Imm<8> imm8) {
return PLIHandler(*this);
}
bool ThumbTranslatorVisitor::thumb32_PLI_imm12([[maybe_unused]] Reg n,
[[maybe_unused]] Imm<12> imm12) {
return PLIHandler(*this);
}
bool ThumbTranslatorVisitor::thumb32_PLI_reg([[maybe_unused]] Reg n,
[[maybe_unused]] Imm<2> imm2,
Reg m) {
if (m == Reg::PC) {
return UnpredictableInstruction();
}
return PLIHandler(*this);
}
bool ThumbTranslatorVisitor::thumb32_LDRB_lit(bool U, Reg t, Imm<12> imm12) {
return LoadByteLiteral(*this, U, t, imm12, &IREmitter::ZeroExtendByteToWord);
}
bool ThumbTranslatorVisitor::thumb32_LDRB_imm8(Reg n, Reg t, bool P, bool U, bool W, Imm<8> imm8) {
if (t == Reg::PC && W) {
return UnpredictableInstruction();
}
if (W && n == t) {
return UnpredictableInstruction();
}
if (!P && !W) {
return UndefinedInstruction();
}
return LoadByteImmediate(*this, n, t, P, U, W, Imm<12>{imm8.ZeroExtend()},
&IREmitter::ZeroExtendByteToWord);
}
bool ThumbTranslatorVisitor::thumb32_LDRB_imm12(Reg n, Reg t, Imm<12> imm12) {
return LoadByteImmediate(*this, n, t, true, true, false, imm12,
&IREmitter::ZeroExtendByteToWord);
}
bool ThumbTranslatorVisitor::thumb32_LDRB_reg(Reg n, Reg t, Imm<2> imm2, Reg m) {
return LoadByteRegister(*this, n, t, imm2, m, &IREmitter::ZeroExtendByteToWord);
}
bool ThumbTranslatorVisitor::thumb32_LDRBT(Reg n, Reg t, Imm<8> imm8) {
// TODO: Add an unpredictable instruction path if this
// is executed in hypervisor mode if we ever support
// privileged execution modes.
if (t == Reg::PC) {
return UnpredictableInstruction();
}
// Treat it as a normal LDRB, given we don't support
// execution levels other than EL0 currently.
return thumb32_LDRB_imm8(n, t, true, true, false, imm8);
}
bool ThumbTranslatorVisitor::thumb32_LDRSB_lit(bool U, Reg t, Imm<12> imm12) {
return LoadByteLiteral(*this, U, t, imm12, &IREmitter::SignExtendByteToWord);
}
bool ThumbTranslatorVisitor::thumb32_LDRSB_imm8(Reg n, Reg t, bool P, bool U, bool W, Imm<8> imm8) {
if (t == Reg::PC && W) {
return UnpredictableInstruction();
}
if (W && n == t) {
return UnpredictableInstruction();
}
if (!P && !W) {
return UndefinedInstruction();
}
return LoadByteImmediate(*this, n, t, P, U, W, Imm<12>{imm8.ZeroExtend()},
&IREmitter::SignExtendByteToWord);
}
bool ThumbTranslatorVisitor::thumb32_LDRSB_imm12(Reg n, Reg t, Imm<12> imm12) {
return LoadByteImmediate(*this, n, t, true, true, false, imm12,
&IREmitter::SignExtendByteToWord);
}
bool ThumbTranslatorVisitor::thumb32_LDRSB_reg(Reg n, Reg t, Imm<2> imm2, Reg m) {
return LoadByteRegister(*this, n, t, imm2, m, &IREmitter::SignExtendByteToWord);
}
bool ThumbTranslatorVisitor::thumb32_LDRSBT(Reg n, Reg t, Imm<8> imm8) {
// TODO: Add an unpredictable instruction path if this
// is executed in hypervisor mode if we ever support
// privileged execution modes.
if (t == Reg::PC) {
return UnpredictableInstruction();
}
// Treat it as a normal LDRSB, given we don't support
// execution levels other than EL0 currently.
return thumb32_LDRSB_imm8(n, t, true, true, false, imm8);
}
} // namespace Dynarmic::A32

View File

@@ -0,0 +1,11 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2021 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#include "frontend/A32/translate/impl/translate_thumb.h"
namespace Dynarmic::A32 {
} // namespace Dynarmic::A32

View File

@@ -0,0 +1,11 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2021 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#include "frontend/A32/translate/impl/translate_thumb.h"
namespace Dynarmic::A32 {
} // namespace Dynarmic::A32

View File

@@ -0,0 +1,50 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2021 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#include "frontend/A32/translate/impl/translate_thumb.h"
namespace Dynarmic::A32 {
template <typename StoreRegFn>
static bool StoreRegister(ThumbTranslatorVisitor& v, Reg n, Reg t, Imm<2> imm2, Reg m, StoreRegFn store_fn) {
if (n == Reg::PC) {
return v.UndefinedInstruction();
}
if (t == Reg::PC || m == Reg::PC) {
return v.UnpredictableInstruction();
}
const auto reg_m = v.ir.GetRegister(m);
const auto reg_n = v.ir.GetRegister(n);
const auto reg_t = v.ir.GetRegister(t);
const auto shift_amount = v.ir.Imm8(static_cast<u8>(imm2.ZeroExtend()));
const auto offset = v.ir.LogicalShiftLeft(reg_m, shift_amount);
const auto offset_address = v.ir.Add(reg_n, offset);
store_fn(offset_address, reg_t);
return true;
}
bool ThumbTranslatorVisitor::thumb32_STRB(Reg n, Reg t, Imm<2> imm2, Reg m) {
return StoreRegister(*this, n, t, imm2, m, [this](const IR::U32& offset_address, const IR::U32& data) {
ir.WriteMemory8(offset_address, ir.LeastSignificantByte(data));
});
}
bool ThumbTranslatorVisitor::thumb32_STRH(Reg n, Reg t, Imm<2> imm2, Reg m) {
return StoreRegister(*this, n, t, imm2, m, [this](const IR::U32& offset_address, const IR::U32& data) {
ir.WriteMemory16(offset_address, ir.LeastSignificantHalf(data));
});
}
bool ThumbTranslatorVisitor::thumb32_STR_reg(Reg n, Reg t, Imm<2> imm2, Reg m) {
return StoreRegister(*this, n, t, imm2, m, [this](const IR::U32& offset_address, const IR::U32& data) {
ir.WriteMemory32(offset_address, data);
});
}
} // namespace Dynarmic::A32

View File

@@ -56,6 +56,27 @@ struct ThumbTranslatorVisitor final {
return ThumbExpandImm_C(i, imm3, imm8, ir.Imm1(0)).imm32;
}
IR::ResultAndCarry<IR::U32> EmitImmShift(IR::U32 value, ShiftType type, Imm<3> imm3, Imm<2> imm2, IR::U1 carry_in) {
u8 imm5_value = concatenate(imm3, imm2).ZeroExtend<u8>();
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();
}
A32::IREmitter ir;
ConditionalState cond_state = ConditionalState::None;
TranslationOptions options;
@@ -67,6 +88,8 @@ struct ThumbTranslatorVisitor final {
bool UndefinedInstruction();
bool RaiseException(Exception exception);
IR::ResultAndCarry<IR::U32> 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);
@@ -148,21 +171,107 @@ struct ThumbTranslatorVisitor final {
bool thumb16_B_t1(Cond cond, Imm<8> imm8);
bool thumb16_B_t2(Imm<11> imm11);
// thumb32 data processing (shifted register) instructions
bool thumb32_TST_reg(Reg n, Imm<3> imm3, Imm<2> imm2, ShiftType type, Reg m);
bool thumb32_AND_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, ShiftType type, Reg m);
bool thumb32_BIC_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, ShiftType type, Reg m);
bool thumb32_MOV_reg(bool S, Imm<3> imm3, Reg d, Imm<2> imm2, ShiftType type, Reg m);
bool thumb32_ORR_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, ShiftType type, Reg m);
bool thumb32_MVN_reg(bool S, Imm<3> imm3, Reg d, Imm<2> imm2, ShiftType type, Reg m);
bool thumb32_ORN_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, ShiftType type, Reg m);
bool thumb32_TEQ_reg(Reg n, Imm<3> imm3, Imm<2> imm2, ShiftType type, Reg m);
bool thumb32_EOR_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, ShiftType type, Reg m);
bool thumb32_PKH(Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, Imm<1> tb, Reg m);
bool thumb32_CMN_reg(Reg n, Imm<3> imm3, Imm<2> imm2, ShiftType type, Reg m);
bool thumb32_ADD_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, ShiftType type, Reg m);
bool thumb32_ADC_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, ShiftType type, Reg m);
bool thumb32_SBC_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, ShiftType type, Reg m);
bool thumb32_CMP_reg(Reg n, Imm<3> imm3, Imm<2> imm2, ShiftType type, Reg m);
bool thumb32_SUB_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, ShiftType type, Reg m);
bool thumb32_RSB_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, ShiftType type, Reg m);
// thumb32 data processing (modified immediate) instructions
bool thumb32_TST_imm(Imm<1> i, Reg n, Imm<3> imm3, Imm<8> imm8);
bool thumb32_AND_imm(Imm<1> i, bool S, Reg n, Imm<3> imm3, Reg d, Imm<8> imm8);
bool thumb32_BIC_imm(Imm<1> i, bool S, Reg n, Imm<3> imm3, Reg d, Imm<8> imm8);
bool thumb32_MOV_imm(Imm<1> i, bool S, Imm<3> imm3, Reg d, Imm<8> imm8);
bool thumb32_ORR_imm(Imm<1> i, bool S, Reg n, Imm<3> imm3, Reg d, Imm<8> imm8);
bool thumb32_MVN_imm(Imm<1> i, bool S, Imm<3> imm3, Reg d, Imm<8> imm8);
bool thumb32_ORN_imm(Imm<1> i, bool S, Reg n, Imm<3> imm3, Reg d, Imm<8> imm8);
bool thumb32_TEQ_imm(Imm<1> i, Reg n, Imm<3> imm3, Imm<8> imm8);
bool thumb32_EOR_imm(Imm<1> i, bool S, Reg n, Imm<3> imm3, Reg d, Imm<8> imm8);
bool thumb32_CMN_imm(Imm<1> i, Reg n, Imm<3> imm3, Imm<8> imm8);
bool thumb32_ADD_imm_1(Imm<1> i, bool S, Reg n, Imm<3> imm3, Reg d, Imm<8> imm8);
bool thumb32_ADC_imm(Imm<1> i, bool S, Reg n, Imm<3> imm3, Reg d, Imm<8> imm8);
bool thumb32_SBC_imm(Imm<1> i, bool S, Reg n, Imm<3> imm3, Reg d, Imm<8> imm8);
bool thumb32_CMP_imm(Imm<1> i, Reg n, Imm<3> imm3, Imm<8> imm8);
bool thumb32_SUB_imm_1(Imm<1> i, bool S, Reg n, Imm<3> imm3, Reg d, Imm<8> imm8);
bool thumb32_RSB_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_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
bool thumb32_BXJ(Reg m);
bool thumb32_CLREX();
bool thumb32_DMB(Imm<4> option);
bool thumb32_DSB(Imm<4> option);
bool thumb32_ISB(Imm<4> option);
bool thumb32_NOP();
bool thumb32_SEV();
bool thumb32_SEVL();
bool thumb32_UDF();
bool thumb32_WFE();
bool thumb32_WFI();
bool thumb32_YIELD();
// thumb32 branch instructions
bool thumb32_BL_imm(Imm<1> S, Imm<10> hi, Imm<1> j1, Imm<1> j2, Imm<11> lo);
bool thumb32_BLX_imm(Imm<1> S, Imm<10> hi, Imm<1> j1, Imm<1> j2, Imm<11> lo);
bool thumb32_B(Imm<1> S, Imm<10> hi, Imm<1> j1, Imm<1> j2, Imm<11> lo);
bool thumb32_B_cond(Imm<1> S, Cond cond, Imm<6> hi, Imm<1> j1, Imm<1> j2, Imm<11> lo);
// thumb32 store single data item instructions
bool thumb32_STRB(Reg n, Reg t, Imm<2> imm2, Reg m);
bool thumb32_STRH(Reg n, Reg t, Imm<2> imm2, Reg m);
bool thumb32_STR_reg(Reg n, Reg t, Imm<2> imm2, Reg m);
// thumb32 load byte and memory hints
bool thumb32_PLD_lit(bool U, Imm<12> imm12);
bool thumb32_PLD_imm8(bool W, Reg n, Imm<8> imm8);
bool thumb32_PLD_imm12(bool W, Reg n, Imm<12> imm12);
bool thumb32_PLD_reg(bool W, Reg n, Imm<2> imm2, Reg m);
bool thumb32_PLI_lit(bool U, Imm<12> imm12);
bool thumb32_PLI_imm8(Reg n, Imm<8> imm8);
bool thumb32_PLI_imm12(Reg n, Imm<12> imm12);
bool thumb32_PLI_reg(Reg n, Imm<2> imm2, Reg m);
bool thumb32_LDRB_lit(bool U, Reg t, Imm<12> imm12);
bool thumb32_LDRB_reg(Reg n, Reg t, Imm<2> imm2, Reg m);
bool thumb32_LDRB_imm8(Reg n, Reg t, bool P, bool U, bool W, Imm<8> imm8);
bool thumb32_LDRB_imm12(Reg n, Reg t, Imm<12> imm12);
bool thumb32_LDRBT(Reg n, Reg t, Imm<8> imm8);
bool thumb32_LDRSB_lit(bool U, Reg t, Imm<12> imm12);
bool thumb32_LDRSB_reg(Reg n, Reg t, Imm<2> imm2, Reg m);
bool thumb32_LDRSB_imm8(Reg n, Reg t, bool P, bool U, bool W, Imm<8> imm8);
bool thumb32_LDRSB_imm12(Reg n, Reg t, Imm<12> imm12);
bool thumb32_LDRSBT(Reg n, Reg t, Imm<8> imm8);
// thumb32 data processing (register) instructions
bool thumb32_ASR_reg(Reg m, Reg d, Reg s);
bool thumb32_LSL_reg(Reg m, Reg d, Reg s);
bool thumb32_LSR_reg(Reg m, Reg d, Reg s);
bool thumb32_ROR_reg(Reg m, Reg d, Reg s);
bool thumb32_SXTB(Reg d, SignExtendRotation rotate, Reg m);
bool thumb32_SXTB16(Reg d, SignExtendRotation rotate, Reg m);
bool thumb32_SXTAB(Reg n, Reg d, SignExtendRotation rotate, Reg m);

View File

@@ -176,4 +176,25 @@ bool ThumbTranslatorVisitor::RaiseException(Exception exception) {
return false;
}
IR::ResultAndCarry<IR::U32> ThumbTranslatorVisitor::EmitImmShift(IR::U32 value, ShiftType type, Imm<5> imm5, IR::U1 carry_in) {
u8 imm5_value = imm5.ZeroExtend<u8>();
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

View File

@@ -60,6 +60,7 @@ INST(WFE, "WFE", "11010
INST(WFI, "WFI", "11010101000000110010000001111111")
INST(SEV, "SEV", "11010101000000110010000010011111")
INST(SEVL, "SEVL", "11010101000000110010000010111111")
//INST(DGH, "DGH", "11010101000000110010000011011111") // v8.6
//INST(XPAC_1, "XPACD, XPACI, XPACLRI", "110110101100000101000D11111ddddd")
//INST(XPAC_2, "XPACD, XPACI, XPACLRI", "11010101000000110010000011111111")
//INST(PACIA_1, "PACIA, PACIA1716, PACIASP, PACIAZ, PACIZA", "110110101100000100Z000nnnnnddddd")
@@ -611,6 +612,12 @@ INST(FMLS_vec_1, "FMLS (vector)", "0Q001
//INST(FMINP_vec_1, "FMINP (vector)", "0Q101110110mmmmm001101nnnnnddddd")
// Data Processing - FP and SIMD - SIMD Three same extra
//INST(SMMLA_vec, "SMMLA", "01001110100mmmmm101001nnnnnddddd") // v8.6
//INST(UMMLA_vec, "UMMLA", "01101110100mmmmm101001nnnnnddddd") // v8.6
//INST(USMMLA_vec, "USMMLA", "01001110100mmmmm101011nnnnnddddd") // v8.6
//INST(SUDOT_element, "SUDOT (by element)", "0Q00111100LMmmmm1111H0nnnnnddddd") // v8.6
//INST(USDOT_element, "USDOT (by_element)", "0Q00111110LMmmmm1111H0nnnnnddddd") // v8.6
//INST(USDOT_vec, "USDOT (vector)", "0Q001110100mmmmm100111nnnnnddddd") // v8.6
INST(SDOT_vec, "SDOT (vector)", "0Q001110zz0mmmmm100101nnnnnddddd")
INST(UDOT_vec, "UDOT (vector)", "0Q101110zz0mmmmm100101nnnnnddddd")
INST(FCMLA_vec, "FCMLA", "0Q101110zz0mmmmm110rr1nnnnnddddd")
@@ -1005,3 +1012,12 @@ INST(FMADD_float, "FMADD", "00011
INST(FMSUB_float, "FMSUB", "00011111yy0mmmmm1aaaaannnnnddddd")
INST(FNMADD_float, "FNMADD", "00011111yy1mmmmm0aaaaannnnnddddd")
INST(FNMSUB_float, "FNMSUB", "00011111yy1mmmmm1aaaaannnnnddddd")
// BFloat16
//INST(BFCVT, "BFCVT", "0001111001100011010000nnnnnddddd") // v8.6
//INST(BFCVTN, "BFCVTN{2}", "0Q00111010100001011010nnnnnddddd") // v8.6
//INST(BFDOT_element, "BFDOT (by element)", "0Q00111101LMmmmm1111H0nnnnnddddd") // v8.6
//INST(BFDOT_vec, "BFDOT (vector)", "0Q101110010mmmmm111111nnnnnddddd") // v8.6
//INST(BFMLALX_element, "BFMLALX (by element)", "0Q00111111LMmmmm1111H0nnnnnddddd") // v8.6
//INST(BFMLALX_vector, "BFMLALX (vector)", "0Q101110110mmmmm111111nnnnnddddd") // v8.6
//INST(BFMMLA, "BFMMLA", "01101110010mmmmm111011nnnnnddddd") // v8.6