citra-emu
/
citra-canary
Archived
1
0
Fork 0

arm_disasm: ARMv6 packing and sign-extend media instructions

PKH, SEL
SXTAB, SXTAB16, SXTB, SXTB16, SXTH, SXTAH
UXTAB, UXTAB16, UXTB, UXTB16, UXTH, UXTAH
This commit is contained in:
aroulin 2015-08-07 10:10:35 +02:00
parent f48a89af8b
commit 47657a1817
2 changed files with 181 additions and 1 deletions

View File

@ -1,6 +1,7 @@
// Copyright 2006 The Android Open Source Project // Copyright 2006 The Android Open Source Project
#include <string> #include <string>
#include <unordered_set>
#include "common/string_util.h" #include "common/string_util.h"
#include "core/arm/disassembler/arm_disasm.h" #include "core/arm/disassembler/arm_disasm.h"
@ -66,10 +67,12 @@ static const char *opcode_names[] = {
"mvn", "mvn",
"nop", "nop",
"orr", "orr",
"pkh",
"pld", "pld",
"rsb", "rsb",
"rsc", "rsc",
"sbc", "sbc",
"sel",
"sev", "sev",
"smlal", "smlal",
"smull", "smull",
@ -88,10 +91,22 @@ static const char *opcode_names[] = {
"swi", "swi",
"swp", "swp",
"swpb", "swpb",
"sxtab",
"sxtab16",
"sxtah",
"sxtb",
"sxtb16",
"sxth",
"teq", "teq",
"tst", "tst",
"umlal", "umlal",
"umull", "umull",
"uxtab",
"uxtab16",
"uxtah",
"uxtb",
"uxtb16",
"uxth",
"wfe", "wfe",
"wfi", "wfi",
"yield", "yield",
@ -236,8 +251,12 @@ std::string ARM_Disasm::Disassemble(uint32_t addr, uint32_t insn)
case OP_WFI: case OP_WFI:
case OP_YIELD: case OP_YIELD:
return DisassembleNoOperands(opcode, insn); return DisassembleNoOperands(opcode, insn);
case OP_PKH:
return DisassemblePKH(insn);
case OP_PLD: case OP_PLD:
return DisassemblePLD(insn); return DisassemblePLD(insn);
case OP_SEL:
return DisassembleSEL(insn);
case OP_STC: case OP_STC:
return "stc"; return "stc";
case OP_SWI: case OP_SWI:
@ -245,6 +264,19 @@ std::string ARM_Disasm::Disassemble(uint32_t addr, uint32_t insn)
case OP_SWP: case OP_SWP:
case OP_SWPB: case OP_SWPB:
return DisassembleSWP(opcode, insn); return DisassembleSWP(opcode, insn);
case OP_SXTAB:
case OP_SXTAB16:
case OP_SXTAH:
case OP_SXTB:
case OP_SXTB16:
case OP_SXTH:
case OP_UXTAB:
case OP_UXTAB16:
case OP_UXTAH:
case OP_UXTB:
case OP_UXTB16:
case OP_UXTH:
return DisassembleXT(opcode, insn);
case OP_UMLAL: case OP_UMLAL:
case OP_UMULL: case OP_UMULL:
case OP_SMLAL: case OP_SMLAL:
@ -684,6 +716,30 @@ std::string ARM_Disasm::DisassembleNoOperands(Opcode opcode, uint32_t insn)
return Common::StringFromFormat("%s%s", opcode_names[opcode], cond_to_str(cond)); return Common::StringFromFormat("%s%s", opcode_names[opcode], cond_to_str(cond));
} }
std::string ARM_Disasm::DisassemblePKH(uint32_t insn)
{
uint32_t cond = BITS(insn, 28, 31);
uint32_t rn = BITS(insn, 16, 19);
uint32_t rd = BITS(insn, 12, 15);
uint32_t imm5 = BITS(insn, 7, 11);
uint32_t tb = BIT(insn, 6);
uint32_t rm = BITS(insn, 0, 3);
std::string suffix = tb ? "tb" : "bt";
std::string shift = "";
if (tb && imm5 == 0)
imm5 = 32;
if (imm5 > 0) {
shift = tb ? ", ASR" : ", LSL";
shift += " #" + std::to_string(imm5);
}
return Common::StringFromFormat("pkh%s%s\tr%u, r%u, r%u%s", suffix.c_str(), cond_to_str(cond),
rd, rn, rm, shift.c_str());
}
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;
@ -737,6 +793,17 @@ std::string ARM_Disasm::DisassembleREX(Opcode opcode, uint32_t insn) {
} }
} }
std::string ARM_Disasm::DisassembleSEL(uint32_t insn)
{
uint32_t cond = BITS(insn, 28, 31);
uint32_t rn = BITS(insn, 16, 19);
uint32_t rd = BITS(insn, 12, 15);
uint32_t rm = BITS(insn, 0, 3);
return Common::StringFromFormat("%s%s\tr%u, r%u, r%u", opcode_names[OP_SEL], cond_to_str(cond),
rd, rn, rm);
}
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;
@ -756,6 +823,30 @@ std::string ARM_Disasm::DisassembleSWP(Opcode opcode, uint32_t insn)
return Common::StringFromFormat("%s%s\tr%d, r%d, [r%d]", opname, cond_to_str(cond), rd, rm, rn); return Common::StringFromFormat("%s%s\tr%d, r%d, [r%d]", opname, cond_to_str(cond), rd, rm, rn);
} }
std::string ARM_Disasm::DisassembleXT(Opcode opcode, uint32_t insn)
{
uint32_t cond = BITS(insn, 28, 31);
uint32_t rn = BITS(insn, 16, 19);
uint32_t rd = BITS(insn, 12, 15);
uint32_t rotate = BITS(insn, 10, 11);
uint32_t rm = BITS(insn, 0, 3);
std::string rn_part = "";
static std::unordered_set<Opcode, std::hash<int>> extend_with_add = {
OP_SXTAB, OP_SXTAB16, OP_SXTAH,
OP_UXTAB, OP_UXTAB16, OP_UXTAH
};
if (extend_with_add.find(opcode) != extend_with_add.end())
rn_part = ", r" + std::to_string(rn);
std::string rotate_part = "";
if (rotate != 0)
rotate_part = ", ROR #" + std::to_string(rotate << 3);
return Common::StringFromFormat("%s%s\tr%u%s, r%u%s", opcode_names[opcode], cond_to_str(cond),
rd, rn_part.c_str(), rm, rotate_part.c_str());
}
Opcode ARM_Disasm::Decode(uint32_t insn) { Opcode ARM_Disasm::Decode(uint32_t insn) {
uint32_t bits27_26 = (insn >> 26) & 0x3; uint32_t bits27_26 = (insn >> 26) & 0x3;
switch (bits27_26) { switch (bits27_26) {
@ -818,7 +909,7 @@ Opcode ARM_Disasm::Decode01(uint32_t insn) {
uint8_t is_reg = (insn >> 25) & 0x1; uint8_t is_reg = (insn >> 25) & 0x1;
uint8_t bit4 = (insn >> 4) & 0x1; uint8_t bit4 = (insn >> 4) & 0x1;
if (is_reg == 1 && bit4 == 1) if (is_reg == 1 && bit4 == 1)
return OP_UNDEFINED; return DecodeMedia(insn);
uint8_t is_load = (insn >> 20) & 0x1; uint8_t is_load = (insn >> 20) & 0x1;
uint8_t is_byte = (insn >> 22) & 0x1; uint8_t is_byte = (insn >> 22) & 0x1;
if ((insn & 0xfd70f000) == 0xf550f000) { if ((insn & 0xfd70f000) == 0xf550f000) {
@ -940,6 +1031,59 @@ Opcode ARM_Disasm::DecodeSyncPrimitive(uint32_t insn) {
} }
} }
Opcode ARM_Disasm::DecodePackingSaturationReversal(uint32_t insn) {
uint32_t op1 = BITS(insn, 20, 22);
uint32_t a = BITS(insn, 16, 19);
uint32_t op2 = BITS(insn, 5, 7);
switch (op1) {
case 0x0:
if (BIT(op2, 0) == 0)
return OP_PKH;
if (op2 == 0x3 && a != 0xf)
return OP_SXTAB16;
if (op2 == 0x3 && a == 0xf)
return OP_SXTB16;
if (op2 == 0x5)
return OP_SEL;
break;
case 0x2:
if (op2 == 0x3 && a != 0xf)
return OP_SXTAB;
if (op2 == 0x3 && a == 0xf)
return OP_SXTB;
break;
case 0x3:
if (op2 == 0x3 && a != 0xf)
return OP_SXTAH;
if (op2 == 0x3 && a == 0xf)
return OP_SXTH;
break;
case 0x4:
if (op2 == 0x3 && a != 0xf)
return OP_UXTAB16;
if (op2 == 0x3 && a == 0xf)
return OP_UXTB16;
break;
case 0x6:
if (op2 == 0x3 && a != 0xf)
return OP_UXTAB;
if (op2 == 0x3 && a == 0xf)
return OP_UXTB;
break;
case 0x7:
if (op2 == 0x3 && a != 0xf)
return OP_UXTAH;
if (op2 == 0x3 && a == 0xf)
return OP_UXTH;
break;
default:
break;
}
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) {
@ -999,6 +1143,23 @@ Opcode ARM_Disasm::DecodeMSRImmAndHints(uint32_t insn) {
return OP_MSR; return OP_MSR;
} }
Opcode ARM_Disasm::DecodeMedia(uint32_t insn) {
uint32_t op1 = BITS(insn, 20, 24);
uint32_t rd = BITS(insn, 12, 15);
uint32_t op2 = BITS(insn, 5, 7);
uint32_t rn = BITS(insn, 0, 3);
switch (BITS(op1, 3, 4)) {
case 0x1:
// Packing, unpacking, saturation, and reversal
return DecodePackingSaturationReversal(insn);
default:
break;
}
return OP_UNDEFINED;
}
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

@ -48,10 +48,12 @@ enum Opcode {
OP_MVN, OP_MVN,
OP_NOP, OP_NOP,
OP_ORR, OP_ORR,
OP_PKH,
OP_PLD, OP_PLD,
OP_RSB, OP_RSB,
OP_RSC, OP_RSC,
OP_SBC, OP_SBC,
OP_SEL,
OP_SEV, OP_SEV,
OP_SMLAL, OP_SMLAL,
OP_SMULL, OP_SMULL,
@ -70,10 +72,22 @@ enum Opcode {
OP_SWI, OP_SWI,
OP_SWP, OP_SWP,
OP_SWPB, OP_SWPB,
OP_SXTAB,
OP_SXTAB16,
OP_SXTAH,
OP_SXTB,
OP_SXTB16,
OP_SXTH,
OP_TEQ, OP_TEQ,
OP_TST, OP_TST,
OP_UMLAL, OP_UMLAL,
OP_UMULL, OP_UMULL,
OP_UXTAB,
OP_UXTAB16,
OP_UXTAH,
OP_UXTB,
OP_UXTB16,
OP_UXTH,
OP_WFE, OP_WFE,
OP_WFI, OP_WFI,
OP_YIELD, OP_YIELD,
@ -132,8 +146,10 @@ class ARM_Disasm {
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 DecodeSyncPrimitive(uint32_t insn);
static Opcode DecodePackingSaturationReversal(uint32_t insn);
static Opcode DecodeMUL(uint32_t insn); static Opcode DecodeMUL(uint32_t insn);
static Opcode DecodeMSRImmAndHints(uint32_t insn); static Opcode DecodeMSRImmAndHints(uint32_t insn);
static Opcode DecodeMedia(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);
@ -152,8 +168,11 @@ class ARM_Disasm {
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 DisassembleNoOperands(Opcode opcode, uint32_t insn);
static std::string DisassemblePKH(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 DisassembleREX(Opcode opcode, uint32_t insn);
static std::string DisassembleSEL(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);
static std::string DisassembleXT(Opcode opcode, uint32_t insn);
}; };