From 90d317b8689169de22a9edcc16f373ecd3f1eb1e Mon Sep 17 00:00:00 2001 From: MerryMage Date: Wed, 20 Jul 2016 15:34:17 +0100 Subject: [PATCH] Implement memory endianness. Implement Thumb SETEND instruction. --- src/backend_x64/emit_x64.cpp | 16 ++++++++++++-- src/backend_x64/emit_x64.h | 1 + src/frontend/decoder/thumb16.h | 2 +- .../disassembler/disassembler_thumb.cpp | 4 ++++ src/frontend/ir/ir_emitter.cpp | 22 +++++++++++++++---- src/frontend/ir/ir_emitter.h | 1 + src/frontend/ir/opcodes.inc | 1 + src/frontend/translate/translate_thumb.cpp | 12 ++++++++++ tests/arm/fuzz_thumb.cpp | 4 ++-- 9 files changed, 54 insertions(+), 9 deletions(-) diff --git a/src/backend_x64/emit_x64.cpp b/src/backend_x64/emit_x64.cpp index 16cc642d..98db5feb 100644 --- a/src/backend_x64/emit_x64.cpp +++ b/src/backend_x64/emit_x64.cpp @@ -651,6 +651,13 @@ void EmitX64::EmitByteReverseHalf(IR::Value* value_) { code->ROL(16, R(result), Imm8(8)); } +void EmitX64::EmitByteReverseDual(IR::Value* value_) { + auto value = reinterpret_cast(value_); + + X64Reg result = reg_alloc.UseDefRegister(value->GetArg(0).get(), value); + + code->BSWAP(64, result); +} void EmitX64::EmitReadMemory8(IR::Value* value_) { auto value = reinterpret_cast(value_); @@ -922,8 +929,6 @@ void EmitX64::EmitTerminalReturnToDispatch(IR::Term::ReturnToDispatch, Arm::Loca } void EmitX64::EmitTerminalLinkBlock(IR::Term::LinkBlock terminal, Arm::LocationDescriptor initial_location) { - ASSERT_MSG(terminal.next.EFlag == initial_location.EFlag, "Unimplemented"); - code->MOV(32, MJitStateReg(Arm::Reg::PC), Imm32(terminal.next.arm_pc)); if (terminal.next.TFlag != initial_location.TFlag) { if (terminal.next.TFlag) { @@ -932,6 +937,13 @@ void EmitX64::EmitTerminalLinkBlock(IR::Term::LinkBlock terminal, Arm::LocationD code->AND(32, MJitStateCpsr(), Imm32(~(1 << 5))); } } + if (terminal.next.EFlag != initial_location.EFlag) { + if (terminal.next.EFlag) { + code->OR(32, MJitStateCpsr(), Imm32(1 << 9)); + } else { + code->AND(32, MJitStateCpsr(), Imm32(~(1 << 9))); + } + } routines->GenReturnFromRunCode(code); // TODO: Check cycles, Properly do a link } diff --git a/src/backend_x64/emit_x64.h b/src/backend_x64/emit_x64.h index 8d5380c1..b0d2d5f9 100644 --- a/src/backend_x64/emit_x64.h +++ b/src/backend_x64/emit_x64.h @@ -72,6 +72,7 @@ private: void EmitZeroExtendByteToWord(IR::Value* value); void EmitByteReverseWord(IR::Value* value); void EmitByteReverseHalf(IR::Value* value); + void EmitByteReverseDual(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 911e4eef..d3de70a5 100644 --- a/src/frontend/decoder/thumb16.h +++ b/src/frontend/decoder/thumb16.h @@ -129,7 +129,7 @@ boost::optional&> DecodeThumb16(u16 instruction) { INST(&V::thumb16_UXTB, "UXTB", "1011001011mmmddd"), // v6 INST(&V::thumb16_PUSH, "PUSH", "1011010Mxxxxxxxx"), // v4T INST(&V::thumb16_POP, "POP", "1011110Pxxxxxxxx"), // v4T - //INST(&V::thumb16_SETEND, "SETEND", "101101100101x000"), // v6 + INST(&V::thumb16_SETEND, "SETEND", "101101100101x000"), // v6 //INST(&V::thumb16_CPS, "CPS", "10110110011m0aif"), // v6 INST(&V::thumb16_REV, "REV", "1011101000mmmddd"), // v6 INST(&V::thumb16_REV16, "REV16", "1011101001mmmddd"), // v6 diff --git a/src/frontend/disassembler/disassembler_thumb.cpp b/src/frontend/disassembler/disassembler_thumb.cpp index fad47611..aa77dd07 100644 --- a/src/frontend/disassembler/disassembler_thumb.cpp +++ b/src/frontend/disassembler/disassembler_thumb.cpp @@ -359,6 +359,10 @@ public: return "pop " + RegListStr(reg_list); } + std::string thumb16_SETEND(bool E) { + return Common::StringFromFormat("setend %s", E ? "BE" : "LE"); + } + std::string thumb16_REV(Reg m, Reg d) { return Common::StringFromFormat("rev %s, %s", RegStr(d), RegStr(m)); } diff --git a/src/frontend/ir/ir_emitter.cpp b/src/frontend/ir/ir_emitter.cpp index 0ef1c5cc..8c8df66d 100644 --- a/src/frontend/ir/ir_emitter.cpp +++ b/src/frontend/ir/ir_emitter.cpp @@ -207,21 +207,27 @@ IR::ValuePtr IREmitter::ByteReverseHalf(IR::ValuePtr a) { return Inst(IR::Opcode::ByteReverseHalf, {a}); } +IR::ValuePtr IREmitter::ByteReverseDual(IR::ValuePtr a) { + return Inst(IR::Opcode::ByteReverseDual, {a}); +} IR::ValuePtr IREmitter::ReadMemory8(IR::ValuePtr vaddr) { return Inst(IR::Opcode::ReadMemory8, {vaddr}); } IR::ValuePtr IREmitter::ReadMemory16(IR::ValuePtr vaddr) { - return Inst(IR::Opcode::ReadMemory16, {vaddr}); + auto value = Inst(IR::Opcode::ReadMemory16, {vaddr}); + return current_location.EFlag ? ByteReverseHalf(value) : value; } IR::ValuePtr IREmitter::ReadMemory32(IR::ValuePtr vaddr) { - return Inst(IR::Opcode::ReadMemory32, {vaddr}); + auto value = Inst(IR::Opcode::ReadMemory32, {vaddr}); + return current_location.EFlag ? ByteReverseWord(value) : value; } IR::ValuePtr IREmitter::ReadMemory64(IR::ValuePtr vaddr) { - return Inst(IR::Opcode::ReadMemory64, {vaddr}); + auto value = Inst(IR::Opcode::ReadMemory64, {vaddr}); + return current_location.EFlag ? ByteReverseDual(value) : value; } void IREmitter::WriteMemory8(IR::ValuePtr vaddr, IR::ValuePtr value) { @@ -229,18 +235,26 @@ void IREmitter::WriteMemory8(IR::ValuePtr vaddr, IR::ValuePtr value) { } void IREmitter::WriteMemory16(IR::ValuePtr vaddr, IR::ValuePtr value) { + if (current_location.EFlag) { + value = ByteReverseHalf(value); + } Inst(IR::Opcode::WriteMemory16, {vaddr, value}); } void IREmitter::WriteMemory32(IR::ValuePtr vaddr, IR::ValuePtr value) { + if (current_location.EFlag) { + value = ByteReverseWord(value); + } Inst(IR::Opcode::WriteMemory32, {vaddr, value}); } void IREmitter::WriteMemory64(IR::ValuePtr vaddr, IR::ValuePtr value) { + if (current_location.EFlag) { + value = ByteReverseDual(value); + } Inst(IR::Opcode::WriteMemory64, {vaddr, value}); } - void IREmitter::SetTerm(const IR::Terminal& terminal) { ASSERT_MSG(block.terminal.which() == 0, "Terminal has already been set."); block.terminal = terminal; diff --git a/src/frontend/ir/ir_emitter.h b/src/frontend/ir/ir_emitter.h index 16942c6c..6efccb17 100644 --- a/src/frontend/ir/ir_emitter.h +++ b/src/frontend/ir/ir_emitter.h @@ -77,6 +77,7 @@ public: IR::ValuePtr ZeroExtendByteToWord(IR::ValuePtr a); IR::ValuePtr ByteReverseWord(IR::ValuePtr a); IR::ValuePtr ByteReverseHalf(IR::ValuePtr a); + IR::ValuePtr ByteReverseDual(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 b516dc2e..ada4ce67 100644 --- a/src/frontend/ir/opcodes.inc +++ b/src/frontend/ir/opcodes.inc @@ -45,6 +45,7 @@ OPCODE(ZeroExtendHalfToWord, T::U32, T::U16 OPCODE(ZeroExtendByteToWord, T::U32, T::U8 ) OPCODE(ByteReverseWord, T::U32, T::U32 ) OPCODE(ByteReverseHalf, T::U16, T::U16 ) +OPCODE(ByteReverseDual, T::U64, T::U64 ) // 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 cdd77e7b..072065b7 100644 --- a/src/frontend/translate/translate_thumb.cpp +++ b/src/frontend/translate/translate_thumb.cpp @@ -676,6 +676,18 @@ struct ThumbTranslatorVisitor final { } } + bool thumb16_SETEND(bool E) { + // SETEND + if (E == ir.current_location.EFlag) { + return true; + } + auto next_location = ir.current_location; + next_location.arm_pc += 2; + next_location.EFlag = E; + ir.SetTerm(IR::Term::LinkBlock{next_location}); + return false; + } + bool thumb16_REV(Reg m, Reg d) { // REV , // Rd cannot encode R15. diff --git a/tests/arm/fuzz_thumb.cpp b/tests/arm/fuzz_thumb.cpp index b7a8cdb1..ba343996 100644 --- a/tests/arm/fuzz_thumb.cpp +++ b/tests/arm/fuzz_thumb.cpp @@ -247,7 +247,7 @@ void FuzzJitThumb(const size_t instruction_count, const size_t instructions_to_e } TEST_CASE("Fuzz Thumb instructions set 1", "[JitX64][Thumb]") { - const std::array instructions = {{ + const std::array instructions = {{ ThumbInstGen("00000xxxxxxxxxxx"), // LSL , , # ThumbInstGen("00001xxxxxxxxxxx"), // LSR , , # ThumbInstGen("00010xxxxxxxxxxx"), // ASR , , # @@ -276,7 +276,7 @@ TEST_CASE("Fuzz Thumb instructions set 1", "[JitX64][Thumb]") { ThumbInstGen("10111100xxxxxxxx", // POP (P = 0) [](u16 inst){ return Dynarmic::Common::Bits<0, 7>(inst) != 0; }), // Empty reg_list is UNPREDICTABLE ThumbInstGen("1100xxxxxxxxxxxx"), // STMIA/LDMIA - //ThumbInstGen("101101100101x000"), // SETEND + ThumbInstGen("101101100101x000"), // SETEND }}; auto instruction_select = [&]() -> u16 {