From f732fbb8855e634ea42b5f205da15b653d6aa3f3 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Sat, 7 Mar 2015 22:27:44 +0100 Subject: [PATCH] ARM64 emitter: Add MRS/MSR support (only for the flags register). Add some more to ARM64 Disasm --- Common/Arm64Emitter.cpp | 42 +++++++++++++++++++++++++++++++++-------- Common/Arm64Emitter.h | 12 ++++++++++++ Core/Util/DisArm64.cpp | 29 +++++++++++++++++++++++++--- 3 files changed, 72 insertions(+), 11 deletions(-) diff --git a/Common/Arm64Emitter.cpp b/Common/Arm64Emitter.cpp index 61edcd9b8..65c9299c6 100644 --- a/Common/Arm64Emitter.cpp +++ b/Common/Arm64Emitter.cpp @@ -909,6 +909,9 @@ void ARM64XEmitter::B(CCFlags cond, const void* ptr) _assert_msg_(DYNA_REC, distance >= -0xFFFFF && distance < 0xFFFFF, "%s: Received too large distance: %lx", __FUNCTION__, (int)distance); + // Let's not overrun the opcode bits with the sign extension. + distance &= 0x7FFFF; + Write32((0x54 << 24) | (distance << 5) | cond); } @@ -1007,18 +1010,41 @@ void ARM64XEmitter::_MSR(PStateField field, u8 imm) u32 op1 = 0, op2 = 0; switch (field) { - case FIELD_SPSel: - op1 = 0; op2 = 5; + case FIELD_SPSel: op1 = 0; op2 = 5; break; + case FIELD_DAIFSet: op1 = 3; op2 = 6; break; + case FIELD_DAIFClr: op1 = 3; op2 = 7; break; + default: + _assert_msg_(JIT, false, "Invalid PStateField to do a imm move to"); + break; + } + EncodeSystemInst(0, op1, 4, imm, op2, WSP); +} + +static void GetSystemReg(PStateField field, int &o0, int &op1, int &CRn, int &CRm, int &op2) { + switch (field) { + case FIELD_NZCV: + o0 = 3; op1 = 3; CRn = 4; CRm = 2; op2 = 0; break; - case FIELD_DAIFSet: - op1 = 3; op2 = 6; - break; - case FIELD_DAIFClr: - op1 = 3; op2 = 7; + default: + _assert_msg_(JIT, false, "Invalid PStateField to do a register move from/to"); break; } - EncodeSystemInst(0, op1, 3, imm, op2, WSP); } + +void ARM64XEmitter::_MSR(PStateField field, ARM64Reg Rt) { + int o0, op1, CRn, CRm, op2; + _assert_msg_(JIT, Is64Bit(Rt), "MSR: Rt must be 64-bit"); + GetSystemReg(field, o0, op1, CRn, CRm, op2); + EncodeSystemInst(o0, op1, CRn, CRm, op2, DecodeReg(Rt)); +} + +void ARM64XEmitter::MRS(ARM64Reg Rt, PStateField field) { + int o0, op1, CRn, CRm, op2; + _assert_msg_(JIT, Is64Bit(Rt), "MRS: Rt must be 64-bit"); + GetSystemReg(field, o0, op1, CRn, CRm, op2); + EncodeSystemInst(o0 | 4, op1, CRn, CRm, op2, DecodeReg(Rt)); +} + void ARM64XEmitter::HINT(SystemHint op) { EncodeSystemInst(0, 3, 2, 0, op, WSP); diff --git a/Common/Arm64Emitter.h b/Common/Arm64Emitter.h index c06e65c39..a74e083c1 100644 --- a/Common/Arm64Emitter.h +++ b/Common/Arm64Emitter.h @@ -129,6 +129,13 @@ enum ExtendType EXTEND_SXTX = 7, }; +// The only system registers accessible from EL0 (user space) +enum SystemRegister { // Three digits : Op1, CRm, Op2 + SYSREG_NZCV = 0x320, + SYSREG_FPCR = 0x340, + SYSREG_FPSR = 0x341, +}; + struct FixupBranch { u8* ptr; @@ -157,6 +164,7 @@ enum PStateField FIELD_SPSel = 0, FIELD_DAIFSet, FIELD_DAIFClr, + FIELD_NZCV, }; enum SystemHint @@ -414,6 +422,10 @@ public: // System void _MSR(PStateField field, u8 imm); + + void _MSR(PStateField field, ARM64Reg Rt); + void MRS(ARM64Reg Rt, PStateField field); + void HINT(SystemHint op); void CLREX(); void DSB(BarrierType type); diff --git a/Core/Util/DisArm64.cpp b/Core/Util/DisArm64.cpp index dcd51c622..4a3514807 100644 --- a/Core/Util/DisArm64.cpp +++ b/Core/Util/DisArm64.cpp @@ -16,7 +16,10 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. // Basic ARM64 disassembler. + // No promises of accuracy, mostly just made to debug JIT code. +// Contains just enough to sort of understand what's going on without having to resort to an +// external disassembler all the time... #include @@ -43,8 +46,20 @@ static void BranchExceptionAndSystem(uint32_t w, uint64_t addr, Instruction *ins int offset = SignExtend26(w & 0x03FFFFFF) << 2; uint64_t target = addr + offset; snprintf(instr->text, sizeof(instr->text), "b%s %08x%08x", (w >> 31) ? "l" : "", (target >> 32), (target & 0xFFFFFFFF)); + } else if (((w >> 25) & 0x3F) == 0x1A) { + snprintf(instr->text, sizeof(instr->text), "(comp & branch %08x)", w); + } else if (((w >> 25) & 0x3F) == 0x1B) { + snprintf(instr->text, sizeof(instr->text), "(test & branch %08x)", w); + } else if (((w >> 25) & 0x7F) == 0x2A) { + snprintf(instr->text, sizeof(instr->text), "(cond-branch %08x)", w); + } else if ((w >> 24) == 0xD4) { + snprintf(instr->text, sizeof(instr->text), "(exception-gen %08x)", w); + } else if (((w >> 20) & 0xFFC) == 0xD50) { + snprintf(instr->text, sizeof(instr->text), "(system-reg %08x)", w); + } else if (((w >> 25) & 0x7F) == 0x6B) { + snprintf(instr->text, sizeof(instr->text), "(branch-reg %08x)", w); } else { - snprintf(instr->text, sizeof(instr->text), "(BRX %08x)", w); + snprintf(instr->text, sizeof(instr->text), "(BRX ?? %08x)", w); } } @@ -56,12 +71,20 @@ static void DataProcessingRegister(uint32_t w, uint64_t addr, Instruction *instr int rd = w & 0x1F; int rn = (w >> 5) & 0x1F; int rm = (w >> 16) & 0x1F; + char r = ((w >> 31) & 1) ? 'x' : 'w'; if (((w >> 21) & 0xF) == 9) { bool S = (w >> 29) & 1; - char r = ((w >> 31) & 1) ? 'x' : 'w'; bool sub = (w >> 30) & 1; - snprintf(instr->text, sizeof(instr->text), "%s%s %c%d, %c%d, %c%d", sub ? "sub" : "add", S ? "s" : "", r, rd, r, rn, r, rm); + if (rd == 31 && S) { + // It's a CMP + snprintf(instr->text, sizeof(instr->text), "%s%s %c%d, %c%d", "cmp", S ? "s" : "", r, rn, r, rm); + } else { + snprintf(instr->text, sizeof(instr->text), "%s%s %c%d, %c%d, %c%d", sub ? "sub" : "add", S ? "s" : "", r, rd, r, rn, r, rm); + } + } else if (((w >> 23) & 0x3f) == 0x25) { + int imm16 = (w >> 5) & 0xFFFF; + snprintf(instr->text, sizeof(instr->text), "%s %c%d, 0x%04x", "movew", r, rd, imm16); } else { snprintf(instr->text, sizeof(instr->text), "(DPR %08x)", w); }