diff --git a/src/backend_x64/emit_x64.cpp b/src/backend_x64/emit_x64.cpp index 9d648636..9625e995 100644 --- a/src/backend_x64/emit_x64.cpp +++ b/src/backend_x64/emit_x64.cpp @@ -602,6 +602,59 @@ void EmitX64::EmitNot(IR::Value* value_) { code->NOT(32, R(result)); } +void EmitX64::EmitSignExtendHalfToWord(IR::Value* value_) { + auto value = reinterpret_cast(value_); + + // TODO: Remove unnecessary mov that may occur here + X64Reg result = reg_alloc.UseDefRegister(value->GetArg(0).get(), value); + + code->MOVSX(32, 16, result, R(result)); +} + +void EmitX64::EmitSignExtendByteToWord(IR::Value* value_) { + auto value = reinterpret_cast(value_); + + // TODO: Remove unnecessary mov that may occur here + X64Reg result = reg_alloc.UseDefRegister(value->GetArg(0).get(), value); + + code->MOVSX(32, 8, result, R(result)); +} + +void EmitX64::EmitZeroExtendHalfToWord(IR::Value* value_) { + auto value = reinterpret_cast(value_); + + // TODO: Remove unnecessary mov that may occur here + X64Reg result = reg_alloc.UseDefRegister(value->GetArg(0).get(), value); + + code->MOVZX(32, 16, result, R(result)); +} + +void EmitX64::EmitZeroExtendByteToWord(IR::Value* value_) { + auto value = reinterpret_cast(value_); + + // TODO: Remove unnecessary mov that may occur here + X64Reg result = reg_alloc.UseDefRegister(value->GetArg(0).get(), value); + + code->MOVZX(32, 8, result, R(result)); +} + +void EmitX64::EmitByteReverseWord(IR::Value* value_) { + auto value = reinterpret_cast(value_); + + X64Reg result = reg_alloc.UseDefRegister(value->GetArg(0).get(), value); + + code->BSWAP(32, result); +} + +void EmitX64::EmitByteReverseHalf(IR::Value* value_) { + auto value = reinterpret_cast(value_); + + X64Reg result = reg_alloc.UseDefRegister(value->GetArg(0).get(), value); + + code->ROL(16, R(result), Imm8(8)); +} + + void EmitX64::EmitReadMemory8(IR::Value* value_) { auto value = reinterpret_cast(value_); diff --git a/src/backend_x64/emit_x64.h b/src/backend_x64/emit_x64.h index f61fe513..da19408a 100644 --- a/src/backend_x64/emit_x64.h +++ b/src/backend_x64/emit_x64.h @@ -66,6 +66,12 @@ private: void EmitEor(IR::Value* value); void EmitOr(IR::Value* value); void EmitNot(IR::Value* value); + void EmitSignExtendHalfToWord(IR::Value* value); + void EmitSignExtendByteToWord(IR::Value* value); + void EmitZeroExtendHalfToWord(IR::Value* value); + void EmitZeroExtendByteToWord(IR::Value* value); + void EmitByteReverseWord(IR::Value* value); + void EmitByteReverseHalf(IR::Value* value); void EmitReadMemory8(IR::Value* value); void EmitReadMemory16(IR::Value* value); void EmitReadMemory32(IR::Value* value); diff --git a/src/frontend/decoder/thumb16.h b/src/frontend/decoder/thumb16.h index 35f8845f..25893785 100644 --- a/src/frontend/decoder/thumb16.h +++ b/src/frontend/decoder/thumb16.h @@ -56,7 +56,7 @@ private: }; template -const std::array, 36> g_thumb16_instruction_table = { +const std::array, 43> g_thumb16_instruction_table = { #define INST(fn, name, bitstring) detail::detail::GetMatcher(name, bitstring) @@ -119,17 +119,17 @@ const std::array, 36> g_thumb16_instruction_table = { // Miscellaneous 16-bit instructions //INST(&V::thumb16_ADD_spsp, "ADD (imm to SP)", "101100000vvvvvvv"), // v4T //INST(&V::thumb16_SUB_spsp, "SUB (imm from SP)", "101100001vvvvvvv"), // v4T - //INST(&V::thumb16_SXTH, "SXTH", "1011001000mmmddd"), // v6 - //INST(&V::thumb16_SXTB, "SXTB", "1011001001mmmddd"), // v6 - //INST(&V::thumb16_UXTH, "UXTH", "1011001010mmmddd"), // v6 - //INST(&V::thumb16_UXTB, "UXTB", "1011001011mmmddd"), // v6 + INST(&V::thumb16_SXTH, "SXTH", "1011001000mmmddd"), // v6 + INST(&V::thumb16_SXTB, "SXTB", "1011001001mmmddd"), // v6 + INST(&V::thumb16_UXTH, "UXTH", "1011001010mmmddd"), // v6 + INST(&V::thumb16_UXTB, "UXTB", "1011001011mmmddd"), // v6 //INST(&V::thumb16_PUSH, "PUSH", "1011010rxxxxxxxx"), // v4T //INST(&V::thumb16_POP, "POP", "1011110rxxxxxxxx"), // v4T //INST(&V::thumb16_SETEND, "SETEND", "101101100101x000"), // v6 //INST(&V::thumb16_CPS, "CPS", "10110110011m0aif"), // v6 - //INST(&V::thumb16_REV, "REV", "1011101000nnnddd"), // v6 - //INST(&V::thumb16_REV16, "REV16", "1011101001nnnddd"), // v6 - //INST(&V::thumb16_REVSH, "REVSH", "1011101011nnnddd"), // v6 + INST(&V::thumb16_REV, "REV", "1011101000mmmddd"), // v6 + INST(&V::thumb16_REV16, "REV16", "1011101001mmmddd"), // v6 + INST(&V::thumb16_REVSH, "REVSH", "1011101011mmmddd"), // v6 //INST(&V::thumb16_BKPT, "BKPT", "10111110xxxxxxxx"), // v5 // Store/Load multiple registers diff --git a/src/frontend/disassembler/disassembler_thumb.cpp b/src/frontend/disassembler/disassembler_thumb.cpp index e17fe8b2..ae796202 100644 --- a/src/frontend/disassembler/disassembler_thumb.cpp +++ b/src/frontend/disassembler/disassembler_thumb.cpp @@ -244,6 +244,34 @@ public: return Common::StringFromFormat("ldr %s, [%s, #%u]", RegStr(t), RegStr(n), imm32); } + std::string thumb16_SXTH(Reg m, Reg d) { + return Common::StringFromFormat("sxth %s, %s", RegStr(d), RegStr(m)); + } + + std::string thumb16_SXTB(Reg m, Reg d) { + return Common::StringFromFormat("sxtb %s, %s", RegStr(d), RegStr(m)); + } + + std::string thumb16_UXTH(Reg m, Reg d) { + return Common::StringFromFormat("uxth %s, %s", RegStr(d), RegStr(m)); + } + + std::string thumb16_UXTB(Reg m, Reg d) { + return Common::StringFromFormat("uxtb %s, %s", RegStr(d), RegStr(m)); + } + + std::string thumb16_REV(Reg m, Reg d) { + return Common::StringFromFormat("rev %s, %s", RegStr(d), RegStr(m)); + } + + std::string thumb16_REV16(Reg m, Reg d) { + return Common::StringFromFormat("rev16 %s, %s", RegStr(d), RegStr(m)); + } + + std::string thumb16_REVSH(Reg m, Reg d) { + return Common::StringFromFormat("revsh %s, %s", RegStr(d), RegStr(m)); + } + std::string thumb16_UDF() { return Common::StringFromFormat("udf"); } diff --git a/src/frontend/ir/ir_emitter.cpp b/src/frontend/ir/ir_emitter.cpp index d57929fe..1549ab31 100644 --- a/src/frontend/ir/ir_emitter.cpp +++ b/src/frontend/ir/ir_emitter.cpp @@ -171,6 +171,31 @@ IR::ValuePtr IREmitter::Not(IR::ValuePtr a) { return Inst(IR::Opcode::Not, {a}); } +IR::ValuePtr IREmitter::SignExtendHalfToWord(IR::ValuePtr a) { + return Inst(IR::Opcode::SignExtendHalfToWord, {a}); +} + +IR::ValuePtr IREmitter::SignExtendByteToWord(IR::ValuePtr a) { + return Inst(IR::Opcode::SignExtendByteToWord, {a}); +} + +IR::ValuePtr IREmitter::ZeroExtendHalfToWord(IR::ValuePtr a) { + return Inst(IR::Opcode::ZeroExtendHalfToWord, {a}); +} + +IR::ValuePtr IREmitter::ZeroExtendByteToWord(IR::ValuePtr a) { + return Inst(IR::Opcode::ZeroExtendByteToWord, {a}); +} + +IR::ValuePtr IREmitter::ByteReverseWord(IR::ValuePtr a) { + return Inst(IR::Opcode::ByteReverseWord, {a}); +} + +IR::ValuePtr IREmitter::ByteReverseHalf(IR::ValuePtr a) { + return Inst(IR::Opcode::ByteReverseHalf, {a}); +} + + IR::ValuePtr IREmitter::ReadMemory8(IR::ValuePtr vaddr) { return Inst(IR::Opcode::ReadMemory8, {vaddr}); } diff --git a/src/frontend/ir/ir_emitter.h b/src/frontend/ir/ir_emitter.h index df1f1070..a3a7d244 100644 --- a/src/frontend/ir/ir_emitter.h +++ b/src/frontend/ir/ir_emitter.h @@ -68,6 +68,12 @@ public: IR::ValuePtr Eor(IR::ValuePtr a, IR::ValuePtr b); IR::ValuePtr Or(IR::ValuePtr a, IR::ValuePtr b); IR::ValuePtr Not(IR::ValuePtr a); + IR::ValuePtr SignExtendHalfToWord(IR::ValuePtr a); + IR::ValuePtr SignExtendByteToWord(IR::ValuePtr a); + IR::ValuePtr ZeroExtendHalfToWord(IR::ValuePtr a); + IR::ValuePtr ZeroExtendByteToWord(IR::ValuePtr a); + IR::ValuePtr ByteReverseWord(IR::ValuePtr a); + IR::ValuePtr ByteReverseHalf(IR::ValuePtr a); IR::ValuePtr ReadMemory8(IR::ValuePtr vaddr); IR::ValuePtr ReadMemory16(IR::ValuePtr vaddr); diff --git a/src/frontend/ir/opcodes.inc b/src/frontend/ir/opcodes.inc index db787890..b516dc2e 100644 --- a/src/frontend/ir/opcodes.inc +++ b/src/frontend/ir/opcodes.inc @@ -39,6 +39,12 @@ OPCODE(And, T::U32, T::U32, T::U32 OPCODE(Eor, T::U32, T::U32, T::U32 ) OPCODE(Or, T::U32, T::U32, T::U32 ) OPCODE(Not, T::U32, T::U32 ) +OPCODE(SignExtendHalfToWord, T::U32, T::U16 ) +OPCODE(SignExtendByteToWord, T::U32, T::U8 ) +OPCODE(ZeroExtendHalfToWord, T::U32, T::U16 ) +OPCODE(ZeroExtendByteToWord, T::U32, T::U8 ) +OPCODE(ByteReverseWord, T::U32, T::U32 ) +OPCODE(ByteReverseHalf, T::U16, T::U16 ) // Memory access OPCODE(ReadMemory8, T::U8, T::U32 ) diff --git a/src/frontend/translate/translate_thumb.cpp b/src/frontend/translate/translate_thumb.cpp index a6a1ad2a..47cd841a 100644 --- a/src/frontend/translate/translate_thumb.cpp +++ b/src/frontend/translate/translate_thumb.cpp @@ -440,6 +440,68 @@ struct ThumbTranslatorVisitor final { return true; } + bool thumb16_SXTH(Reg m, Reg d) { + // SXTH , + // Rd cannot encode R15. + auto half = ir.LeastSignificantHalf(ir.GetRegister(m)); + ir.SetRegister(d, ir.SignExtendHalfToWord(half)); + return true; + } + + bool thumb16_SXTB(Reg m, Reg d) { + // SXTB , + // Rd cannot encode R15. + auto byte = ir.LeastSignificantByte(ir.GetRegister(m)); + ir.SetRegister(d, ir.SignExtendByteToWord(byte)); + return true; + } + + bool thumb16_UXTH(Reg m, Reg d) { + // UXTH , + // Rd cannot encode R15. + auto half = ir.LeastSignificantHalf(ir.GetRegister(m)); + ir.SetRegister(d, ir.ZeroExtendHalfToWord(half)); + return true; + } + + bool thumb16_UXTB(Reg m, Reg d) { + // UXTB , + // Rd cannot encode R15. + auto byte = ir.LeastSignificantByte(ir.GetRegister(m)); + ir.SetRegister(d, ir.ZeroExtendByteToWord(byte)); + return true; + } + + bool thumb16_REV(Reg m, Reg d) { + // REV , + // Rd cannot encode R15. + ir.SetRegister(d, ir.ByteReverseWord(ir.GetRegister(m))); + return true; + } + + bool thumb16_REV16(Reg m, Reg d) { + // REV16 , + // Rd cannot encode R15. + // TODO: Consider optimizing + auto Rm = ir.GetRegister(m); + auto upper_half = ir.LeastSignificantHalf(ir.LogicalShiftRight(Rm, ir.Imm8(16), ir.Imm1(0)).result); + auto lower_half = ir.LeastSignificantHalf(Rm); + auto rev_upper_half = ir.ZeroExtendHalfToWord(ir.ByteReverseHalf(upper_half)); + auto rev_lower_half = ir.ZeroExtendHalfToWord(ir.ByteReverseHalf(lower_half)); + auto result = ir.Or(ir.LogicalShiftLeft(rev_upper_half, ir.Imm8(16), ir.Imm1(0)).result, + rev_lower_half); + ir.SetRegister(d, result); + return true; + } + + bool thumb16_REVSH(Reg m, Reg d) { + // REVSH , + // Rd cannot encode R15. + auto rev_half = ir.ByteReverseHalf(ir.LeastSignificantHalf(ir.GetRegister(m))); + ir.SetRegister(d, ir.SignExtendHalfToWord(rev_half)); + return true; + } + bool thumb16_UDF() { return InterpretThisInstruction(); }