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

arm_disasm: ARMv6 mul/div and abs media instructions

SMLAD, SMUAD, SMLSD, SMUSD, SMLALD, SMLSLD,
SMMLA, SMMUL, SMMLS
USAD8, USADA8
This commit is contained in:
aroulin 2015-08-10 18:21:34 +02:00
parent 4a1db13072
commit 38c87733d9
2 changed files with 119 additions and 1 deletions

View File

@ -92,8 +92,17 @@ static const char *opcode_names[] = {
"shsax", "shsax",
"shsub16", "shsub16",
"shsub8", "shsub8",
"smlad",
"smlal", "smlal",
"smlald",
"smlsd",
"smlsld",
"smmla",
"smmls",
"smmul",
"smuad",
"smull", "smull",
"smusd",
"ssat", "ssat",
"ssat16", "ssat16",
"ssax", "ssax",
@ -139,6 +148,8 @@ static const char *opcode_names[] = {
"uqsax", "uqsax",
"uqsub16", "uqsub16",
"uqsub8", "uqsub8",
"usad8",
"usada8",
"usat", "usat",
"usat16", "usat16",
"usax", "usax",
@ -341,6 +352,18 @@ std::string ARM_Disasm::Disassemble(uint32_t addr, uint32_t insn)
return DisassembleREV(opcode, insn); return DisassembleREV(opcode, insn);
case OP_SEL: case OP_SEL:
return DisassembleSEL(insn); return DisassembleSEL(insn);
case OP_SMLAD:
case OP_SMLALD:
case OP_SMLSD:
case OP_SMLSLD:
case OP_SMMLA:
case OP_SMMLS:
case OP_SMMUL:
case OP_SMUAD:
case OP_SMUSD:
case OP_USAD8:
case OP_USADA8:
return DisassembleMediaMulDiv(opcode, insn);
case OP_SSAT: case OP_SSAT:
case OP_SSAT16: case OP_SSAT16:
case OP_USAT: case OP_USAT:
@ -503,6 +526,38 @@ std::string ARM_Disasm::DisassembleCLZ(uint32_t insn)
return Common::StringFromFormat("clz%s\tr%d, r%d", cond_to_str(cond), rd, rm); return Common::StringFromFormat("clz%s\tr%d, r%d", cond_to_str(cond), rd, rm);
} }
std::string ARM_Disasm::DisassembleMediaMulDiv(Opcode opcode, uint32_t insn) {
uint32_t cond = BITS(insn, 28, 31);
uint32_t rd = BITS(insn, 16, 19);
uint32_t ra = BITS(insn, 12, 15);
uint32_t rm = BITS(insn, 8, 11);
uint32_t m = BIT(insn, 5);
uint32_t rn = BITS(insn, 0, 3);
std::string cross = "";
if (m) {
if (opcode == OP_SMMLA || opcode == OP_SMMUL || opcode == OP_SMMLS)
cross = "r";
else
cross = "x";
}
std::string ext_reg = "";
std::unordered_set<Opcode, std::hash<int>> with_ext_reg = {
OP_SMLAD, OP_SMLSD, OP_SMMLA, OP_SMMLS, OP_USADA8
};
if (with_ext_reg.find(opcode) != with_ext_reg.end())
ext_reg = Common::StringFromFormat(", r%u", ra);
std::string rd_low = "";
if (opcode == OP_SMLALD || opcode == OP_SMLSLD)
rd_low = Common::StringFromFormat("r%u, ", ra);
return Common::StringFromFormat("%s%s%s\t%sr%u, r%u, r%u%s", opcode_names[opcode],
cross.c_str(), cond_to_str(cond), rd_low.c_str(), rd, rn, rm,
ext_reg.c_str());
}
std::string ARM_Disasm::DisassembleMemblock(Opcode opcode, uint32_t insn) std::string ARM_Disasm::DisassembleMemblock(Opcode opcode, uint32_t insn)
{ {
std::string tmp_list; std::string tmp_list;
@ -1339,11 +1394,52 @@ Opcode ARM_Disasm::DecodeMSRImmAndHints(uint32_t insn) {
return OP_MSR; return OP_MSR;
} }
Opcode ARM_Disasm::DecodeMediaMulDiv(uint32_t insn) {
uint32_t op1 = BITS(insn, 20, 22);
uint32_t op2_h = BITS(insn, 6, 7);
uint32_t a = BITS(insn, 12, 15);
switch (op1) {
case 0x0:
if (op2_h == 0x0) {
if (a != 0xf)
return OP_SMLAD;
else
return OP_SMUAD;
} else if (op2_h == 0x1) {
if (a != 0xf)
return OP_SMLSD;
else
return OP_SMUSD;
}
break;
case 0x4:
if (op2_h == 0x0)
return OP_SMLALD;
else if (op2_h == 0x1)
return OP_SMLSLD;
break;
case 0x5:
if (op2_h == 0x0) {
if (a != 0xf)
return OP_SMMLA;
else
return OP_SMMUL;
} else if (op2_h == 0x3) {
return OP_SMMLS;
}
break;
default:
break;
}
return OP_UNDEFINED;
}
Opcode ARM_Disasm::DecodeMedia(uint32_t insn) { Opcode ARM_Disasm::DecodeMedia(uint32_t insn) {
uint32_t op1 = BITS(insn, 20, 24); uint32_t op1 = BITS(insn, 20, 24);
uint32_t rd = BITS(insn, 12, 15); uint32_t rd = BITS(insn, 12, 15);
uint32_t op2 = BITS(insn, 5, 7); uint32_t op2 = BITS(insn, 5, 7);
uint32_t rn = BITS(insn, 0, 3);
switch (BITS(op1, 3, 4)) { switch (BITS(op1, 3, 4)) {
case 0x0: case 0x0:
@ -1352,6 +1448,15 @@ Opcode ARM_Disasm::DecodeMedia(uint32_t insn) {
case 0x1: case 0x1:
// Packing, unpacking, saturation, and reversal // Packing, unpacking, saturation, and reversal
return DecodePackingSaturationReversal(insn); return DecodePackingSaturationReversal(insn);
case 0x2:
// Signed multiply, signed and unsigned divide
return DecodeMediaMulDiv(insn);
case 0x3:
if (op2 == 0 && rd == 0xf)
return OP_USAD8;
if (op2 == 0 && rd != 0xf)
return OP_USADA8;
break;
default: default:
break; break;
} }

View File

@ -73,8 +73,17 @@ enum Opcode {
OP_SHSAX, OP_SHSAX,
OP_SHSUB16, OP_SHSUB16,
OP_SHSUB8, OP_SHSUB8,
OP_SMLAD,
OP_SMLAL, OP_SMLAL,
OP_SMLALD,
OP_SMLSD,
OP_SMLSLD,
OP_SMMLA,
OP_SMMLS,
OP_SMMUL,
OP_SMUAD,
OP_SMULL, OP_SMULL,
OP_SMUSD,
OP_SSAT, OP_SSAT,
OP_SSAT16, OP_SSAT16,
OP_SSAX, OP_SSAX,
@ -120,6 +129,8 @@ enum Opcode {
OP_UQSAX, OP_UQSAX,
OP_UQSUB16, OP_UQSUB16,
OP_UQSUB8, OP_UQSUB8,
OP_USAD8,
OP_USADA8,
OP_USAT, OP_USAT,
OP_USAT16, OP_USAT16,
OP_USAX, OP_USAX,
@ -193,6 +204,7 @@ class ARM_Disasm {
static Opcode DecodePackingSaturationReversal(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 DecodeMediaMulDiv(uint32_t insn);
static Opcode DecodeMedia(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);
@ -202,6 +214,7 @@ class ARM_Disasm {
static std::string DisassembleBX(uint32_t insn); static std::string DisassembleBX(uint32_t insn);
static std::string DisassembleBKPT(uint32_t insn); static std::string DisassembleBKPT(uint32_t insn);
static std::string DisassembleCLZ(uint32_t insn); static std::string DisassembleCLZ(uint32_t insn);
static std::string DisassembleMediaMulDiv(Opcode opcode, uint32_t insn);
static std::string DisassembleMemblock(Opcode opcode, uint32_t insn); static std::string DisassembleMemblock(Opcode opcode, uint32_t insn);
static std::string DisassembleMem(uint32_t insn); static std::string DisassembleMem(uint32_t insn);
static std::string DisassembleMemHalf(uint32_t insn); static std::string DisassembleMemHalf(uint32_t insn);