mirror of
https://github.com/citra-mirror/citra.git
synced 2024-08-19 18:13:21 +02:00
Merge pull request #1022 from aroulin/disas-missing-v6k-instructions
Disassembler: ARMv6K instructions
This commit is contained in:
commit
4821652241
@ -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;
|
||||||
|
@ -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);
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user