From 7a9bdc8f21e1e4accc7838e3f2a9936b0600a9d8 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Tue, 9 Mar 2021 16:49:31 -0500 Subject: [PATCH 1/3] thumb32: Implement LDRH variants --- src/frontend/A32/decoder/thumb32.inc | 10 +-- .../translate/impl/thumb32_load_halfword.cpp | 75 +++++++++++++++++++ .../A32/translate/impl/translate_thumb.h | 7 ++ 3 files changed, 87 insertions(+), 5 deletions(-) diff --git a/src/frontend/A32/decoder/thumb32.inc b/src/frontend/A32/decoder/thumb32.inc index 0179bce3..36aeb21d 100644 --- a/src/frontend/A32/decoder/thumb32.inc +++ b/src/frontend/A32/decoder/thumb32.inc @@ -161,11 +161,11 @@ INST(thumb32_LDRSB_imm8, "LDRSB (imm8)", "111110010001nnnntttt1P INST(thumb32_LDRSB_imm12, "LDRSB (imm12)", "111110011001nnnnttttiiiiiiiiiiii") // Load Halfword and Memory Hints -//INST(thumb32_LDRH_lit, "LDRH (lit)", "11111000-0111111----------------") -//INST(thumb32_LDRH_reg, "LDRH (reg)", "111110000011--------000000------") -//INST(thumb32_LDRHT, "LDRHT", "111110000011--------1110--------") -//INST(thumb32_LDRH_imm8, "LDRH (imm8)", "111110000011--------1-----------") -//INST(thumb32_LDRH_imm12, "LDRH (imm12)", "111110001011--------------------") +INST(thumb32_LDRH_lit, "LDRH (lit)", "11111000U0111111ttttiiiiiiiiiiii") +INST(thumb32_LDRH_reg, "LDRH (reg)", "111110000011nnnntttt000000iimmmm") +INST(thumb32_LDRHT, "LDRHT", "111110000011nnnntttt1110iiiiiiii") +INST(thumb32_LDRH_imm8, "LDRH (imm8)", "111110000011nnnntttt1PUWiiiiiiii") +INST(thumb32_LDRH_imm12, "LDRH (imm12)", "111110001011nnnnttttiiiiiiiiiiii") //INST(thumb32_LDRSH_lit, "LDRSH (lit)", "11111001-0111111----------------") //INST(thumb32_LDRSH_reg, "LDRSH (reg)", "111110010011--------000000------") //INST(thumb32_LDRSHT, "LDRSHT", "111110010011--------1110--------") diff --git a/src/frontend/A32/translate/impl/thumb32_load_halfword.cpp b/src/frontend/A32/translate/impl/thumb32_load_halfword.cpp index 5f4e4104..73b07238 100644 --- a/src/frontend/A32/translate/impl/thumb32_load_halfword.cpp +++ b/src/frontend/A32/translate/impl/thumb32_load_halfword.cpp @@ -7,5 +7,80 @@ namespace Dynarmic::A32 { +bool ThumbTranslatorVisitor::thumb32_LDRH_lit(bool U, Reg t, Imm<12> imm12) { + const auto imm32 = imm12.ZeroExtend(); + const auto base = ir.AlignPC(4); + const auto address = U ? (base + imm32) : (base - imm32); + const auto data = ir.ZeroExtendHalfToWord(ir.ReadMemory16(ir.Imm32(address))); + + ir.SetRegister(t, data); + return true; +} + +bool ThumbTranslatorVisitor::thumb32_LDRH_reg(Reg n, Reg t, Imm<2> imm2, Reg m) { + if (m == Reg::PC) { + return UnpredictableInstruction(); + } + + const IR::U32 reg_m = ir.GetRegister(m); + const IR::U32 reg_n = ir.GetRegister(n); + const IR::U32 offset = ir.LogicalShiftLeft(reg_m, ir.Imm8(imm2.ZeroExtend())); + const IR::U32 address = ir.Add(reg_n, offset); + const IR::U32 data = ir.ZeroExtendHalfToWord(ir.ReadMemory16(address)); + + ir.SetRegister(t, data); + return true; +} + +bool ThumbTranslatorVisitor::thumb32_LDRH_imm8(Reg n, Reg t, bool P, bool U, bool W, Imm<8> imm8) { + if (!P && !W) { + return UndefinedInstruction(); + } + if (t == Reg::PC && W) { + return UnpredictableInstruction(); + } + if (W && n == t) { + return UnpredictableInstruction(); + } + + const u32 imm32 = imm8.ZeroExtend(); + const IR::U32 reg_n = ir.GetRegister(n); + const IR::U32 offset_address = U ? ir.Add(reg_n, ir.Imm32(imm32)) + : ir.Sub(reg_n, ir.Imm32(imm32)); + const IR::U32 address = P ? offset_address + : reg_n; + const IR::U32 data = ir.ZeroExtendHalfToWord(ir.ReadMemory16(address)); + + if (W) { + ir.SetRegister(n, offset_address); + } + + ir.SetRegister(t, data); + return true; +} + +bool ThumbTranslatorVisitor::thumb32_LDRH_imm12(Reg n, Reg t, Imm<12> imm12) { + const auto imm32 = imm12.ZeroExtend(); + const auto reg_n = ir.GetRegister(n); + const auto address = ir.Add(reg_n, ir.Imm32(imm32)); + const auto data = ir.ZeroExtendHalfToWord(ir.ReadMemory16(address)); + + ir.SetRegister(t, data); + return true; +} + +bool ThumbTranslatorVisitor::thumb32_LDRHT(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 levels. + + if (t == Reg::PC) { + return UnpredictableInstruction(); + } + + // Treat it as a normal LDRH, given we don't support + // execution levels other than EL0 currently. + return thumb32_LDRH_imm8(n, t, true, true, false, imm8); +} } // namespace Dynarmic::A32 diff --git a/src/frontend/A32/translate/impl/translate_thumb.h b/src/frontend/A32/translate/impl/translate_thumb.h index 0bbe6e28..045432f4 100644 --- a/src/frontend/A32/translate/impl/translate_thumb.h +++ b/src/frontend/A32/translate/impl/translate_thumb.h @@ -267,6 +267,13 @@ struct ThumbTranslatorVisitor final { bool thumb32_LDRSB_imm12(Reg n, Reg t, Imm<12> imm12); bool thumb32_LDRSBT(Reg n, Reg t, Imm<8> imm8); + // thumb32 load halfword instructions + bool thumb32_LDRH_lit(bool U, Reg t, Imm<12> imm12); + bool thumb32_LDRH_reg(Reg n, Reg t, Imm<2> imm2, Reg m); + bool thumb32_LDRH_imm8(Reg n, Reg t, bool P, bool U, bool W, Imm<8> imm8); + bool thumb32_LDRH_imm12(Reg n, Reg t, Imm<12> imm12); + bool thumb32_LDRHT(Reg n, Reg t, Imm<8> imm8); + // thumb32 load word instructions bool thumb32_LDR_lit(bool U, Reg t, Imm<12> imm12); bool thumb32_LDR_reg(Reg n, Reg t, Imm<2> imm2, Reg m); From 921998f6e9d91b7bd60abbe5a3b86420409805c8 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Tue, 9 Mar 2021 17:20:55 -0500 Subject: [PATCH 2/3] thumb32: Implement LDRSH variants --- src/frontend/A32/decoder/thumb32.inc | 18 +-- .../translate/impl/thumb32_load_halfword.cpp | 125 +++++++++++++----- .../A32/translate/impl/translate_thumb.h | 5 + 3 files changed, 104 insertions(+), 44 deletions(-) diff --git a/src/frontend/A32/decoder/thumb32.inc b/src/frontend/A32/decoder/thumb32.inc index 36aeb21d..18e17de4 100644 --- a/src/frontend/A32/decoder/thumb32.inc +++ b/src/frontend/A32/decoder/thumb32.inc @@ -166,15 +166,15 @@ INST(thumb32_LDRH_reg, "LDRH (reg)", "111110000011nnnntttt00 INST(thumb32_LDRHT, "LDRHT", "111110000011nnnntttt1110iiiiiiii") INST(thumb32_LDRH_imm8, "LDRH (imm8)", "111110000011nnnntttt1PUWiiiiiiii") INST(thumb32_LDRH_imm12, "LDRH (imm12)", "111110001011nnnnttttiiiiiiiiiiii") -//INST(thumb32_LDRSH_lit, "LDRSH (lit)", "11111001-0111111----------------") -//INST(thumb32_LDRSH_reg, "LDRSH (reg)", "111110010011--------000000------") -//INST(thumb32_LDRSHT, "LDRSHT", "111110010011--------1110--------") -//INST(thumb32_LDRSH_imm8, "LDRSH (imm8)", "111110010011--------1-----------") -//INST(thumb32_LDRSH_imm12, "LDRSH (imm12)", "111110011011--------------------") -//INST(thumb32_NOP, "NOP", "111110010011----1111000000------") -//INST(thumb32_NOP, "NOP", "111110010011----11111100--------") -//INST(thumb32_NOP, "NOP", "11111001-01111111111------------") -//INST(thumb32_NOP, "NOP", "111110011011----1111------------") +INST(thumb32_NOP, "NOP", "11111001-01111111111------------") +INST(thumb32_LDRSH_lit, "LDRSH (lit)", "11111001U0111111ttttiiiiiiiiiiii") +INST(thumb32_NOP, "NOP", "111110010011----1111000000------") +INST(thumb32_LDRSH_reg, "LDRSH (reg)", "111110010011nnnntttt000000iimmmm") +INST(thumb32_LDRSHT, "LDRSHT", "111110010011nnnntttt1110iiiiiiii") +INST(thumb32_NOP, "NOP", "111110010011----11111100--------") +INST(thumb32_NOP, "NOP", "111110011011----1111------------") +INST(thumb32_LDRSH_imm8, "LDRSH (imm8)", "111110010011nnnntttt1PUWiiiiiiii") +INST(thumb32_LDRSH_imm12, "LDRSH (imm12)", "111110011011nnnnttttiiiiiiiiiiii") // Load Word INST(thumb32_LDR_lit, "LDR (lit)", "11111000U1011111ttttiiiiiiiiiiii") diff --git a/src/frontend/A32/translate/impl/thumb32_load_halfword.cpp b/src/frontend/A32/translate/impl/thumb32_load_halfword.cpp index 73b07238..ae41a589 100644 --- a/src/frontend/A32/translate/impl/thumb32_load_halfword.cpp +++ b/src/frontend/A32/translate/impl/thumb32_load_halfword.cpp @@ -7,31 +7,61 @@ namespace Dynarmic::A32 { -bool ThumbTranslatorVisitor::thumb32_LDRH_lit(bool U, Reg t, Imm<12> imm12) { - const auto imm32 = imm12.ZeroExtend(); - const auto base = ir.AlignPC(4); - const auto address = U ? (base + imm32) : (base - imm32); - const auto data = ir.ZeroExtendHalfToWord(ir.ReadMemory16(ir.Imm32(address))); +using ExtensionFunction = IR::U32 (IREmitter::*)(const IR::U16&); - ir.SetRegister(t, data); +static bool LoadHalfLiteral(ThumbTranslatorVisitor& v, bool U, Reg t, Imm<12> imm12, + ExtensionFunction ext_fn) { + const auto imm32 = imm12.ZeroExtend(); + const auto base = v.ir.AlignPC(4); + const auto address = U ? (base + imm32) : (base - imm32); + const auto data = (v.ir.*ext_fn)(v.ir.ReadMemory16(v.ir.Imm32(address))); + + v.ir.SetRegister(t, data); return true; } -bool ThumbTranslatorVisitor::thumb32_LDRH_reg(Reg n, Reg t, Imm<2> imm2, Reg m) { +static bool LoadHalfRegister(ThumbTranslatorVisitor& v, Reg n, Reg t, Imm<2> imm2, Reg m, + ExtensionFunction ext_fn) { if (m == Reg::PC) { - return UnpredictableInstruction(); + return v.UnpredictableInstruction(); } - const IR::U32 reg_m = ir.GetRegister(m); - const IR::U32 reg_n = ir.GetRegister(n); - const IR::U32 offset = ir.LogicalShiftLeft(reg_m, ir.Imm8(imm2.ZeroExtend())); - const IR::U32 address = ir.Add(reg_n, offset); - const IR::U32 data = ir.ZeroExtendHalfToWord(ir.ReadMemory16(address)); + const IR::U32 reg_m = v.ir.GetRegister(m); + const IR::U32 reg_n = v.ir.GetRegister(n); + const IR::U32 offset = v.ir.LogicalShiftLeft(reg_m, v.ir.Imm8(imm2.ZeroExtend())); + const IR::U32 address = v.ir.Add(reg_n, offset); + const IR::U32 data = (v.ir.*ext_fn)(v.ir.ReadMemory16(address)); - ir.SetRegister(t, data); + v.ir.SetRegister(t, data); return true; } +static bool LoadHalfImmediate(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.ReadMemory16(address)); + + if (W) { + v.ir.SetRegister(n, offset_address); + } + + v.ir.SetRegister(t, data); + return true; +} + +bool ThumbTranslatorVisitor::thumb32_LDRH_lit(bool U, Reg t, Imm<12> imm12) { + return LoadHalfLiteral(*this, U, t, imm12, &IREmitter::ZeroExtendHalfToWord); +} + +bool ThumbTranslatorVisitor::thumb32_LDRH_reg(Reg n, Reg t, Imm<2> imm2, Reg m) { + return LoadHalfRegister(*this, n, t, imm2, m, &IREmitter::ZeroExtendHalfToWord); +} + bool ThumbTranslatorVisitor::thumb32_LDRH_imm8(Reg n, Reg t, bool P, bool U, bool W, Imm<8> imm8) { if (!P && !W) { return UndefinedInstruction(); @@ -43,30 +73,13 @@ bool ThumbTranslatorVisitor::thumb32_LDRH_imm8(Reg n, Reg t, bool P, bool U, boo return UnpredictableInstruction(); } - const u32 imm32 = imm8.ZeroExtend(); - const IR::U32 reg_n = ir.GetRegister(n); - const IR::U32 offset_address = U ? ir.Add(reg_n, ir.Imm32(imm32)) - : ir.Sub(reg_n, ir.Imm32(imm32)); - const IR::U32 address = P ? offset_address - : reg_n; - const IR::U32 data = ir.ZeroExtendHalfToWord(ir.ReadMemory16(address)); - - if (W) { - ir.SetRegister(n, offset_address); - } - - ir.SetRegister(t, data); - return true; + return LoadHalfImmediate(*this, n, t, P, U, W, Imm<12>{imm8.ZeroExtend()}, + &IREmitter::ZeroExtendHalfToWord); } bool ThumbTranslatorVisitor::thumb32_LDRH_imm12(Reg n, Reg t, Imm<12> imm12) { - const auto imm32 = imm12.ZeroExtend(); - const auto reg_n = ir.GetRegister(n); - const auto address = ir.Add(reg_n, ir.Imm32(imm32)); - const auto data = ir.ZeroExtendHalfToWord(ir.ReadMemory16(address)); - - ir.SetRegister(t, data); - return true; + return LoadHalfImmediate(*this, n, t, true, true, false, imm12, + &IREmitter::ZeroExtendHalfToWord); } bool ThumbTranslatorVisitor::thumb32_LDRHT(Reg n, Reg t, Imm<8> imm8) { @@ -83,4 +96,46 @@ bool ThumbTranslatorVisitor::thumb32_LDRHT(Reg n, Reg t, Imm<8> imm8) { return thumb32_LDRH_imm8(n, t, true, true, false, imm8); } +bool ThumbTranslatorVisitor::thumb32_LDRSH_lit(bool U, Reg t, Imm<12> imm12) { + return LoadHalfLiteral(*this, U, t, imm12, &IREmitter::SignExtendHalfToWord); +} + +bool ThumbTranslatorVisitor::thumb32_LDRSH_reg(Reg n, Reg t, Imm<2> imm2, Reg m) { + return LoadHalfRegister(*this, n, t, imm2, m, &IREmitter::SignExtendHalfToWord); +} + +bool ThumbTranslatorVisitor::thumb32_LDRSH_imm8(Reg n, Reg t, bool P, bool U, bool W, Imm<8> imm8) { + if (!P && !W) { + return UndefinedInstruction(); + } + if (t == Reg::PC && W) { + return UnpredictableInstruction(); + } + if (W && n == t) { + return UnpredictableInstruction(); + } + + return LoadHalfImmediate(*this, n, t, P, U, W, Imm<12>{imm8.ZeroExtend()}, + &IREmitter::SignExtendHalfToWord); +} + +bool ThumbTranslatorVisitor::thumb32_LDRSH_imm12(Reg n, Reg t, Imm<12> imm12) { + return LoadHalfImmediate(*this, n, t, true, true, false, imm12, + &IREmitter::SignExtendHalfToWord); +} + +bool ThumbTranslatorVisitor::thumb32_LDRSHT(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 levels. + + if (t == Reg::PC) { + return UnpredictableInstruction(); + } + + // Treat it as a normal LDRSH, given we don't support + // execution levels other than EL0 currently. + return thumb32_LDRSH_imm8(n, t, true, true, false, imm8); +} + } // namespace Dynarmic::A32 diff --git a/src/frontend/A32/translate/impl/translate_thumb.h b/src/frontend/A32/translate/impl/translate_thumb.h index 045432f4..d85942fd 100644 --- a/src/frontend/A32/translate/impl/translate_thumb.h +++ b/src/frontend/A32/translate/impl/translate_thumb.h @@ -273,6 +273,11 @@ struct ThumbTranslatorVisitor final { bool thumb32_LDRH_imm8(Reg n, Reg t, bool P, bool U, bool W, Imm<8> imm8); bool thumb32_LDRH_imm12(Reg n, Reg t, Imm<12> imm12); bool thumb32_LDRHT(Reg n, Reg t, Imm<8> imm8); + bool thumb32_LDRSH_lit(bool U, Reg t, Imm<12> imm12); + bool thumb32_LDRSH_reg(Reg n, Reg t, Imm<2> imm2, Reg m); + bool thumb32_LDRSH_imm8(Reg n, Reg t, bool P, bool U, bool W, Imm<8> imm8); + bool thumb32_LDRSH_imm12(Reg n, Reg t, Imm<12> imm12); + bool thumb32_LDRSHT(Reg n, Reg t, Imm<8> imm8); // thumb32 load word instructions bool thumb32_LDR_lit(bool U, Reg t, Imm<12> imm12); From fb30922cd1d016493ba9bdd1d72aa8ef3295b2ad Mon Sep 17 00:00:00 2001 From: Lioncash Date: Tue, 9 Mar 2021 18:11:53 -0500 Subject: [PATCH 3/3] thumb32: Add supporting decoder entry for PLD (literal) LDRH (literal)'s pseduocode indicates that cases where Rt specifies the PC, that the instruction should be execured as if it were a PLD instruction. Curiously, however, within the ARM reference manual, the encodings in the case that happens doesn't match up. The bit pattern for LDRH (literal) has bit 21 set to 1, but the encoding of PLD (literal) has bit 21 set to zero for it's only thumb encoding. --- src/frontend/A32/decoder/thumb32.inc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/frontend/A32/decoder/thumb32.inc b/src/frontend/A32/decoder/thumb32.inc index 18e17de4..bf2bc56a 100644 --- a/src/frontend/A32/decoder/thumb32.inc +++ b/src/frontend/A32/decoder/thumb32.inc @@ -142,6 +142,7 @@ INST(thumb32_STR_reg, "STR (reg)", "111110000100nnnntttt00 // Load Byte and Memory Hints INST(thumb32_PLD_lit, "PLD (lit)", "11111000U00111111111iiiiiiiiiiii") +INST(thumb32_PLD_lit, "PLD (lit)", "11111000U01111111111iiiiiiiiiiii") INST(thumb32_PLD_reg, "PLD (reg)", "1111100000W1nnnn1111000000iimmmm") INST(thumb32_PLD_imm8, "PLD (imm8)", "1111100000W1nnnn11111100iiiiiiii") INST(thumb32_PLD_imm12, "PLD (imm12)", "1111100010W1nnnn1111iiiiiiiiiiii")