citra-emu
/
citra
Archived
1
0
Fork 0

Merge pull request #1022 from aroulin/disas-missing-v6k-instructions

Disassembler: ARMv6K instructions
This commit is contained in:
Lioncash 2015-08-06 18:09:52 -04:00
commit 4821652241
2 changed files with 153 additions and 6 deletions

View File

@ -4,6 +4,7 @@
#include "common/string_util.h" #include "common/string_util.h"
#include "core/arm/disassembler/arm_disasm.h" #include "core/arm/disassembler/arm_disasm.h"
#include "core/arm/skyeye_common/armsupp.h"
static const char *cond_names[] = { static const char *cond_names[] = {
"eq", "eq",
@ -37,6 +38,7 @@ static const char *opcode_names[] = {
"blx", "blx",
"bx", "bx",
"cdp", "cdp",
"clrex",
"clz", "clz",
"cmn", "cmn",
"cmp", "cmp",
@ -46,6 +48,10 @@ static const char *opcode_names[] = {
"ldr", "ldr",
"ldrb", "ldrb",
"ldrbt", "ldrbt",
"ldrex",
"ldrexb",
"ldrexd",
"ldrexh",
"ldrh", "ldrh",
"ldrsb", "ldrsb",
"ldrsh", "ldrsh",
@ -58,11 +64,13 @@ static const char *opcode_names[] = {
"msr", "msr",
"mul", "mul",
"mvn", "mvn",
"nop",
"orr", "orr",
"pld", "pld",
"rsb", "rsb",
"rsc", "rsc",
"sbc", "sbc",
"sev",
"smlal", "smlal",
"smull", "smull",
"stc", "stc",
@ -70,6 +78,10 @@ static const char *opcode_names[] = {
"str", "str",
"strb", "strb",
"strbt", "strbt",
"strex",
"strexb",
"strexd",
"strexh",
"strh", "strh",
"strt", "strt",
"sub", "sub",
@ -80,6 +92,9 @@ static const char *opcode_names[] = {
"tst", "tst",
"umlal", "umlal",
"umull", "umull",
"wfe",
"wfi",
"yield",
"undefined", "undefined",
"adc", "adc",
@ -172,6 +187,8 @@ std::string ARM_Disasm::Disassemble(uint32_t addr, uint32_t insn)
return DisassembleBX(insn); return DisassembleBX(insn);
case OP_CDP: case OP_CDP:
return "cdp"; return "cdp";
case OP_CLREX:
return "clrex";
case OP_CLZ: case OP_CLZ:
return DisassembleCLZ(insn); return DisassembleCLZ(insn);
case OP_LDC: case OP_LDC:
@ -188,6 +205,15 @@ std::string ARM_Disasm::Disassemble(uint32_t addr, uint32_t insn)
case OP_STRBT: case OP_STRBT:
case OP_STRT: case OP_STRT:
return DisassembleMem(insn); return DisassembleMem(insn);
case OP_LDREX:
case OP_LDREXB:
case OP_LDREXD:
case OP_LDREXH:
case OP_STREX:
case OP_STREXB:
case OP_STREXD:
case OP_STREXH:
return DisassembleREX(opcode, insn);
case OP_LDRH: case OP_LDRH:
case OP_LDRSB: case OP_LDRSB:
case OP_LDRSH: case OP_LDRSH:
@ -204,6 +230,12 @@ std::string ARM_Disasm::Disassemble(uint32_t addr, uint32_t insn)
return DisassembleMSR(insn); return DisassembleMSR(insn);
case OP_MUL: case OP_MUL:
return DisassembleMUL(opcode, insn); return DisassembleMUL(opcode, insn);
case OP_NOP:
case OP_SEV:
case OP_WFE:
case OP_WFI:
case OP_YIELD:
return DisassembleNoOperands(opcode, insn);
case OP_PLD: case OP_PLD:
return DisassemblePLD(insn); return DisassemblePLD(insn);
case OP_STC: case OP_STC:
@ -646,6 +678,12 @@ std::string ARM_Disasm::DisassembleMSR(uint32_t insn)
cond_to_str(cond), pd ? "spsr" : "cpsr", flags, rm); cond_to_str(cond), pd ? "spsr" : "cpsr", flags, rm);
} }
std::string ARM_Disasm::DisassembleNoOperands(Opcode opcode, uint32_t insn)
{
uint32_t cond = BITS(insn, 28, 31);
return Common::StringFromFormat("%s%s", opcode_names[opcode], cond_to_str(cond));
}
std::string ARM_Disasm::DisassemblePLD(uint32_t insn) std::string ARM_Disasm::DisassemblePLD(uint32_t insn)
{ {
uint8_t is_reg = (insn >> 25) & 0x1; uint8_t is_reg = (insn >> 25) & 0x1;
@ -669,6 +707,36 @@ std::string ARM_Disasm::DisassemblePLD(uint32_t insn)
} }
} }
std::string ARM_Disasm::DisassembleREX(Opcode opcode, uint32_t insn) {
uint32_t rn = BITS(insn, 16, 19);
uint32_t rd = BITS(insn, 12, 15);
uint32_t rt = BITS(insn, 0, 3);
uint32_t cond = BITS(insn, 28, 31);
switch (opcode) {
case OP_STREX:
case OP_STREXB:
case OP_STREXH:
return Common::StringFromFormat("%s%s\tr%d, r%d, [r%d]", opcode_names[opcode],
cond_to_str(cond), rd, rt, rn);
case OP_STREXD:
return Common::StringFromFormat("%s%s\tr%d, r%d, r%d, [r%d]", opcode_names[opcode],
cond_to_str(cond), rd, rt, rt + 1, rn);
// for LDREX instructions, rd corresponds to Rt from reference manual
case OP_LDREX:
case OP_LDREXB:
case OP_LDREXH:
return Common::StringFromFormat("%s%s\tr%d, [r%d]", opcode_names[opcode],
cond_to_str(cond), rd, rn);
case OP_LDREXD:
return Common::StringFromFormat("%s%s\tr%d, r%d, [r%d]", opcode_names[opcode],
cond_to_str(cond), rd, rd + 1, rn);
default:
return opcode_names[OP_UNDEFINED];
}
}
std::string ARM_Disasm::DisassembleSWI(uint32_t insn) std::string ARM_Disasm::DisassembleSWI(uint32_t insn)
{ {
uint8_t cond = (insn >> 28) & 0xf; uint8_t cond = (insn >> 28) & 0xf;
@ -721,12 +789,9 @@ Opcode ARM_Disasm::Decode00(uint32_t insn) {
} }
uint32_t bits7_4 = (insn >> 4) & 0xf; uint32_t bits7_4 = (insn >> 4) & 0xf;
if (bits7_4 == 0x9) { if (bits7_4 == 0x9) {
if ((insn & 0x0ff00ff0) == 0x01000090) { uint32_t bit24 = BIT(insn, 24);
// Swp instruction if (bit24) {
uint8_t bit22 = (insn >> 22) & 0x1; return DecodeSyncPrimitive(insn);
if (bit22)
return OP_SWPB;
return OP_SWP;
} }
// One of the multiply instructions // One of the multiply instructions
return DecodeMUL(insn); return DecodeMUL(insn);
@ -739,6 +804,12 @@ Opcode ARM_Disasm::Decode00(uint32_t insn) {
} }
} }
uint32_t op1 = BITS(insn, 20, 24);
if (bit25 && (op1 == 0x12 || op1 == 0x16)) {
// One of the MSR (immediate) and hints instructions
return DecodeMSRImmAndHints(insn);
}
// One of the data processing instructions // One of the data processing instructions
return DecodeALU(insn); return DecodeALU(insn);
} }
@ -754,6 +825,10 @@ Opcode ARM_Disasm::Decode01(uint32_t insn) {
// Pre-load // Pre-load
return OP_PLD; return OP_PLD;
} }
if (insn == 0xf57ff01f) {
// Clear-Exclusive
return OP_CLREX;
}
if (is_load) { if (is_load) {
if (is_byte) { if (is_byte) {
// Load byte // Load byte
@ -844,6 +919,35 @@ Opcode ARM_Disasm::Decode11(uint32_t insn) {
return OP_MCR; return OP_MCR;
} }
Opcode ARM_Disasm::DecodeSyncPrimitive(uint32_t insn) {
uint32_t op = BITS(insn, 20, 23);
uint32_t bit22 = BIT(insn, 22);
switch (op) {
case 0x0:
if (bit22)
return OP_SWPB;
return OP_SWP;
case 0x8:
return OP_STREX;
case 0x9:
return OP_LDREX;
case 0xA:
return OP_STREXD;
case 0xB:
return OP_LDREXD;
case 0xC:
return OP_STREXB;
case 0xD:
return OP_LDREXB;
case 0xE:
return OP_STREXH;
case 0xF:
return OP_LDREXH;
default:
return OP_UNDEFINED;
}
}
Opcode ARM_Disasm::DecodeMUL(uint32_t insn) { Opcode ARM_Disasm::DecodeMUL(uint32_t insn) {
uint8_t bit24 = (insn >> 24) & 0x1; uint8_t bit24 = (insn >> 24) & 0x1;
if (bit24 != 0) { if (bit24 != 0) {
@ -878,6 +982,31 @@ Opcode ARM_Disasm::DecodeMUL(uint32_t insn) {
return OP_SMLAL; return OP_SMLAL;
} }
Opcode ARM_Disasm::DecodeMSRImmAndHints(uint32_t insn) {
uint32_t op = BIT(insn, 22);
uint32_t op1 = BITS(insn, 16, 19);
uint32_t op2 = BITS(insn, 0, 7);
if (op == 0 && op1 == 0) {
switch (op2) {
case 0x0:
return OP_NOP;
case 0x1:
return OP_YIELD;
case 0x2:
return OP_WFE;
case 0x3:
return OP_WFI;
case 0x4:
return OP_SEV;
default:
return OP_UNDEFINED;
}
}
return OP_MSR;
}
Opcode ARM_Disasm::DecodeLDRH(uint32_t insn) { Opcode ARM_Disasm::DecodeLDRH(uint32_t insn) {
uint8_t is_load = (insn >> 20) & 0x1; uint8_t is_load = (insn >> 20) & 0x1;
uint8_t bits_65 = (insn >> 5) & 0x3; uint8_t bits_65 = (insn >> 5) & 0x3;

View File

@ -20,6 +20,7 @@ enum Opcode {
OP_BLX, OP_BLX,
OP_BX, OP_BX,
OP_CDP, OP_CDP,
OP_CLREX,
OP_CLZ, OP_CLZ,
OP_CMN, OP_CMN,
OP_CMP, OP_CMP,
@ -29,6 +30,10 @@ enum Opcode {
OP_LDR, OP_LDR,
OP_LDRB, OP_LDRB,
OP_LDRBT, OP_LDRBT,
OP_LDREX,
OP_LDREXB,
OP_LDREXD,
OP_LDREXH,
OP_LDRH, OP_LDRH,
OP_LDRSB, OP_LDRSB,
OP_LDRSH, OP_LDRSH,
@ -41,11 +46,13 @@ enum Opcode {
OP_MSR, OP_MSR,
OP_MUL, OP_MUL,
OP_MVN, OP_MVN,
OP_NOP,
OP_ORR, OP_ORR,
OP_PLD, OP_PLD,
OP_RSB, OP_RSB,
OP_RSC, OP_RSC,
OP_SBC, OP_SBC,
OP_SEV,
OP_SMLAL, OP_SMLAL,
OP_SMULL, OP_SMULL,
OP_STC, OP_STC,
@ -53,6 +60,10 @@ enum Opcode {
OP_STR, OP_STR,
OP_STRB, OP_STRB,
OP_STRBT, OP_STRBT,
OP_STREX,
OP_STREXB,
OP_STREXD,
OP_STREXH,
OP_STRH, OP_STRH,
OP_STRT, OP_STRT,
OP_SUB, OP_SUB,
@ -63,6 +74,9 @@ enum Opcode {
OP_TST, OP_TST,
OP_UMLAL, OP_UMLAL,
OP_UMULL, OP_UMULL,
OP_WFE,
OP_WFI,
OP_YIELD,
// Define thumb opcodes // Define thumb opcodes
OP_THUMB_UNDEFINED, OP_THUMB_UNDEFINED,
@ -117,7 +131,9 @@ class ARM_Disasm {
static Opcode Decode01(uint32_t insn); static Opcode Decode01(uint32_t insn);
static Opcode Decode10(uint32_t insn); static Opcode Decode10(uint32_t insn);
static Opcode Decode11(uint32_t insn); static Opcode Decode11(uint32_t insn);
static Opcode DecodeSyncPrimitive(uint32_t insn);
static Opcode DecodeMUL(uint32_t insn); static Opcode DecodeMUL(uint32_t insn);
static Opcode DecodeMSRImmAndHints(uint32_t insn);
static Opcode DecodeLDRH(uint32_t insn); static Opcode DecodeLDRH(uint32_t insn);
static Opcode DecodeALU(uint32_t insn); static Opcode DecodeALU(uint32_t insn);
@ -135,7 +151,9 @@ class ARM_Disasm {
static std::string DisassembleMUL(Opcode opcode, uint32_t insn); static std::string DisassembleMUL(Opcode opcode, uint32_t insn);
static std::string DisassembleMRS(uint32_t insn); static std::string DisassembleMRS(uint32_t insn);
static std::string DisassembleMSR(uint32_t insn); static std::string DisassembleMSR(uint32_t insn);
static std::string DisassembleNoOperands(Opcode opcode, uint32_t insn);
static std::string DisassemblePLD(uint32_t insn); static std::string DisassemblePLD(uint32_t insn);
static std::string DisassembleREX(Opcode opcode, uint32_t insn);
static std::string DisassembleSWI(uint32_t insn); static std::string DisassembleSWI(uint32_t insn);
static std::string DisassembleSWP(Opcode opcode, uint32_t insn); static std::string DisassembleSWP(Opcode opcode, uint32_t insn);
}; };