Implement memory endianness. Implement Thumb SETEND instruction.

This commit is contained in:
MerryMage 2016-07-20 15:34:17 +01:00
parent 98bd7ff6a5
commit 90d317b868
9 changed files with 54 additions and 9 deletions

View file

@ -651,6 +651,13 @@ void EmitX64::EmitByteReverseHalf(IR::Value* value_) {
code->ROL(16, R(result), Imm8(8)); code->ROL(16, R(result), Imm8(8));
} }
void EmitX64::EmitByteReverseDual(IR::Value* value_) {
auto value = reinterpret_cast<IR::Inst*>(value_);
X64Reg result = reg_alloc.UseDefRegister(value->GetArg(0).get(), value);
code->BSWAP(64, result);
}
void EmitX64::EmitReadMemory8(IR::Value* value_) { void EmitX64::EmitReadMemory8(IR::Value* value_) {
auto value = reinterpret_cast<IR::Inst*>(value_); auto value = reinterpret_cast<IR::Inst*>(value_);
@ -922,8 +929,6 @@ void EmitX64::EmitTerminalReturnToDispatch(IR::Term::ReturnToDispatch, Arm::Loca
} }
void EmitX64::EmitTerminalLinkBlock(IR::Term::LinkBlock terminal, Arm::LocationDescriptor initial_location) { 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)); code->MOV(32, MJitStateReg(Arm::Reg::PC), Imm32(terminal.next.arm_pc));
if (terminal.next.TFlag != initial_location.TFlag) { if (terminal.next.TFlag != initial_location.TFlag) {
if (terminal.next.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))); 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 routines->GenReturnFromRunCode(code); // TODO: Check cycles, Properly do a link
} }

View file

@ -72,6 +72,7 @@ private:
void EmitZeroExtendByteToWord(IR::Value* value); void EmitZeroExtendByteToWord(IR::Value* value);
void EmitByteReverseWord(IR::Value* value); void EmitByteReverseWord(IR::Value* value);
void EmitByteReverseHalf(IR::Value* value); void EmitByteReverseHalf(IR::Value* value);
void EmitByteReverseDual(IR::Value* value);
void EmitReadMemory8(IR::Value* value); void EmitReadMemory8(IR::Value* value);
void EmitReadMemory16(IR::Value* value); void EmitReadMemory16(IR::Value* value);
void EmitReadMemory32(IR::Value* value); void EmitReadMemory32(IR::Value* value);

View file

@ -129,7 +129,7 @@ boost::optional<const Thumb16Matcher<V>&> DecodeThumb16(u16 instruction) {
INST(&V::thumb16_UXTB, "UXTB", "1011001011mmmddd"), // v6 INST(&V::thumb16_UXTB, "UXTB", "1011001011mmmddd"), // v6
INST(&V::thumb16_PUSH, "PUSH", "1011010Mxxxxxxxx"), // v4T INST(&V::thumb16_PUSH, "PUSH", "1011010Mxxxxxxxx"), // v4T
INST(&V::thumb16_POP, "POP", "1011110Pxxxxxxxx"), // 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_CPS, "CPS", "10110110011m0aif"), // v6
INST(&V::thumb16_REV, "REV", "1011101000mmmddd"), // v6 INST(&V::thumb16_REV, "REV", "1011101000mmmddd"), // v6
INST(&V::thumb16_REV16, "REV16", "1011101001mmmddd"), // v6 INST(&V::thumb16_REV16, "REV16", "1011101001mmmddd"), // v6

View file

@ -359,6 +359,10 @@ public:
return "pop " + RegListStr(reg_list); 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) { std::string thumb16_REV(Reg m, Reg d) {
return Common::StringFromFormat("rev %s, %s", RegStr(d), RegStr(m)); return Common::StringFromFormat("rev %s, %s", RegStr(d), RegStr(m));
} }

View file

@ -207,21 +207,27 @@ IR::ValuePtr IREmitter::ByteReverseHalf(IR::ValuePtr a) {
return Inst(IR::Opcode::ByteReverseHalf, {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) { IR::ValuePtr IREmitter::ReadMemory8(IR::ValuePtr vaddr) {
return Inst(IR::Opcode::ReadMemory8, {vaddr}); return Inst(IR::Opcode::ReadMemory8, {vaddr});
} }
IR::ValuePtr IREmitter::ReadMemory16(IR::ValuePtr 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) { 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) { 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) { 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) { void IREmitter::WriteMemory16(IR::ValuePtr vaddr, IR::ValuePtr value) {
if (current_location.EFlag) {
value = ByteReverseHalf(value);
}
Inst(IR::Opcode::WriteMemory16, {vaddr, value}); Inst(IR::Opcode::WriteMemory16, {vaddr, value});
} }
void IREmitter::WriteMemory32(IR::ValuePtr vaddr, IR::ValuePtr value) { void IREmitter::WriteMemory32(IR::ValuePtr vaddr, IR::ValuePtr value) {
if (current_location.EFlag) {
value = ByteReverseWord(value);
}
Inst(IR::Opcode::WriteMemory32, {vaddr, value}); Inst(IR::Opcode::WriteMemory32, {vaddr, value});
} }
void IREmitter::WriteMemory64(IR::ValuePtr vaddr, IR::ValuePtr value) { void IREmitter::WriteMemory64(IR::ValuePtr vaddr, IR::ValuePtr value) {
if (current_location.EFlag) {
value = ByteReverseDual(value);
}
Inst(IR::Opcode::WriteMemory64, {vaddr, value}); Inst(IR::Opcode::WriteMemory64, {vaddr, value});
} }
void IREmitter::SetTerm(const IR::Terminal& terminal) { void IREmitter::SetTerm(const IR::Terminal& terminal) {
ASSERT_MSG(block.terminal.which() == 0, "Terminal has already been set."); ASSERT_MSG(block.terminal.which() == 0, "Terminal has already been set.");
block.terminal = terminal; block.terminal = terminal;

View file

@ -77,6 +77,7 @@ public:
IR::ValuePtr ZeroExtendByteToWord(IR::ValuePtr a); IR::ValuePtr ZeroExtendByteToWord(IR::ValuePtr a);
IR::ValuePtr ByteReverseWord(IR::ValuePtr a); IR::ValuePtr ByteReverseWord(IR::ValuePtr a);
IR::ValuePtr ByteReverseHalf(IR::ValuePtr a); IR::ValuePtr ByteReverseHalf(IR::ValuePtr a);
IR::ValuePtr ByteReverseDual(IR::ValuePtr a);
IR::ValuePtr ReadMemory8(IR::ValuePtr vaddr); IR::ValuePtr ReadMemory8(IR::ValuePtr vaddr);
IR::ValuePtr ReadMemory16(IR::ValuePtr vaddr); IR::ValuePtr ReadMemory16(IR::ValuePtr vaddr);

View file

@ -45,6 +45,7 @@ OPCODE(ZeroExtendHalfToWord, T::U32, T::U16
OPCODE(ZeroExtendByteToWord, T::U32, T::U8 ) OPCODE(ZeroExtendByteToWord, T::U32, T::U8 )
OPCODE(ByteReverseWord, T::U32, T::U32 ) OPCODE(ByteReverseWord, T::U32, T::U32 )
OPCODE(ByteReverseHalf, T::U16, T::U16 ) OPCODE(ByteReverseHalf, T::U16, T::U16 )
OPCODE(ByteReverseDual, T::U64, T::U64 )
// Memory access // Memory access
OPCODE(ReadMemory8, T::U8, T::U32 ) OPCODE(ReadMemory8, T::U8, T::U32 )

View file

@ -676,6 +676,18 @@ struct ThumbTranslatorVisitor final {
} }
} }
bool thumb16_SETEND(bool E) {
// SETEND <endianness>
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) { bool thumb16_REV(Reg m, Reg d) {
// REV <Rd>, <Rm> // REV <Rd>, <Rm>
// Rd cannot encode R15. // Rd cannot encode R15.

View file

@ -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]") { TEST_CASE("Fuzz Thumb instructions set 1", "[JitX64][Thumb]") {
const std::array<ThumbInstGen, 24> instructions = {{ const std::array<ThumbInstGen, 25> instructions = {{
ThumbInstGen("00000xxxxxxxxxxx"), // LSL <Rd>, <Rm>, #<imm5> ThumbInstGen("00000xxxxxxxxxxx"), // LSL <Rd>, <Rm>, #<imm5>
ThumbInstGen("00001xxxxxxxxxxx"), // LSR <Rd>, <Rm>, #<imm5> ThumbInstGen("00001xxxxxxxxxxx"), // LSR <Rd>, <Rm>, #<imm5>
ThumbInstGen("00010xxxxxxxxxxx"), // ASR <Rd>, <Rm>, #<imm5> ThumbInstGen("00010xxxxxxxxxxx"), // ASR <Rd>, <Rm>, #<imm5>
@ -276,7 +276,7 @@ TEST_CASE("Fuzz Thumb instructions set 1", "[JitX64][Thumb]") {
ThumbInstGen("10111100xxxxxxxx", // POP (P = 0) ThumbInstGen("10111100xxxxxxxx", // POP (P = 0)
[](u16 inst){ return Dynarmic::Common::Bits<0, 7>(inst) != 0; }), // Empty reg_list is UNPREDICTABLE [](u16 inst){ return Dynarmic::Common::Bits<0, 7>(inst) != 0; }), // Empty reg_list is UNPREDICTABLE
ThumbInstGen("1100xxxxxxxxxxxx"), // STMIA/LDMIA ThumbInstGen("1100xxxxxxxxxxxx"), // STMIA/LDMIA
//ThumbInstGen("101101100101x000"), // SETEND ThumbInstGen("101101100101x000"), // SETEND
}}; }};
auto instruction_select = [&]() -> u16 { auto instruction_select = [&]() -> u16 {