ARM64 emitter: Add MRS/MSR support (only for the flags register). Add some more to ARM64 Disasm

This commit is contained in:
Henrik Rydgard 2015-03-07 22:27:44 +01:00
parent 524583d53e
commit f732fbb885
3 changed files with 72 additions and 11 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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 <stdlib.h>
@ -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);
}