summaryrefslogtreecommitdiffstats
path: root/disassembler/disassembler_arm.cc
diff options
context:
space:
mode:
Diffstat (limited to 'disassembler/disassembler_arm.cc')
-rw-r--r--disassembler/disassembler_arm.cc232
1 files changed, 207 insertions, 25 deletions
diff --git a/disassembler/disassembler_arm.cc b/disassembler/disassembler_arm.cc
index 6239e9a..8d4f3ce 100644
--- a/disassembler/disassembler_arm.cc
+++ b/disassembler/disassembler_arm.cc
@@ -374,7 +374,102 @@ size_t DisassemblerArm::DumpThumb32(std::ostream& os, const uint8_t* instr_ptr)
// uint32_t op5 = (instr >> 4) & 0xF;
ArmRegister Rn(instr, 16);
ArmRegister Rt(instr, 12);
+ ArmRegister Rd(instr, 8);
uint32_t imm8 = instr & 0xFF;
+ if ((op3 & 2) == 2) { // 1x
+ int W = (instr >> 21) & 1;
+ int U = (instr >> 23) & 1;
+ int P = (instr >> 24) & 1;
+
+ if ((op4 & 1) == 1) {
+ opcode << "ldrd";
+ } else {
+ opcode << "strd";
+ }
+ args << Rt << "," << Rd << ", [" << Rn;
+ const char *sign = U ? "+" : "-";
+ if (P == 0 && W == 1) {
+ args << "], #" << sign << imm8;
+ } else {
+ args << ", #" << sign << imm8 << "]";
+ if (W == 1) {
+ args << "!";
+ }
+ }
+ } else { // 0x
+ switch (op4) {
+ case 0:
+ if (op3 == 0) { // op3 is 00, op4 is 00
+ opcode << "strex";
+ args << Rd << ", " << Rt << ", [" << Rn << ", #" << (imm8 << 2) << "]";
+ } else { // op3 is 01, op4 is 00
+ // this is one of strexb, strexh or strexd
+ int op5 = (instr >> 4) & 0xf;
+ switch (op5) {
+ case 4:
+ opcode << "strexb";
+ break;
+ case 5:
+ opcode << "strexh";
+ break;
+ case 7:
+ opcode << "strexd";
+ break;
+ }
+ }
+ break;
+ case 1:
+ if (op3 == 0) { // op3 is 00, op4 is 01
+ opcode << "ldrex";
+ args << Rt << ", [" << Rn << ", #" << (imm8 << 2) << "]";
+ } else { // op3 is 01, op4 is 01
+ // this is one of strexb, strexh or strexd
+ int op5 = (instr >> 4) & 0xf;
+ switch (op5) {
+ case 0:
+ opcode << "tbb";
+ break;
+ case 1:
+ opcode << "tbh";
+ break;
+ case 4:
+ opcode << "ldrexb";
+ break;
+ case 5:
+ opcode << "ldrexh";
+ break;
+ case 7:
+ opcode << "ldrexd";
+ break;
+ }
+ }
+ break;
+ case 2: // op3 is 0x, op4 is 10
+ case 3: // op3 is 0x, op4 is 11
+ if (op4 == 2) {
+ opcode << "strd";
+ } else {
+ opcode << "ldrd";
+ }
+ int W = (instr >> 21) & 1;
+ int U = (instr >> 23) & 1;
+ int P = (instr >> 24) & 1;
+
+ args << Rt << "," << Rd << ", [" << Rn;
+ const char *sign = U ? "+" : "-";
+ if (P == 0 && W == 1) {
+ args << "], #" << sign << imm8;
+ } else {
+ args << ", #" << sign << imm8 << "]";
+ if (W == 1) {
+ args << "!";
+ }
+ }
+ break;
+ }
+ }
+
+
if (op3 == 0 && op4 == 0) { // STREX
ArmRegister Rd(instr, 8);
opcode << "strex";
@@ -519,19 +614,11 @@ size_t DisassemblerArm::DumpThumb32(std::ostream& os, const uint8_t* instr_ptr)
uint32_t op3 = (instr >> 20) & 0x3F;
uint32_t coproc = (instr >> 8) & 0xF;
uint32_t op4 = (instr >> 4) & 0x1;
- if ((op3 == 2 || op3 == 2 || op3 == 6 || op3 == 7) || // 00x1x
- (op3 >= 8 && op3 <= 15) || (op3 >= 16 && op3 <= 31)) { // 001xxx, 01xxxx
- // Extension register load/store instructions
- // |111|1|110|00000|0000|1111|110|000000000|
- // |5 3|2|109|87654|3 0|54 2|10 |87 54 0|
- // |---|-|---|-----|----|----|---|---------|
- // |332|2|222|22222|1111|1111|110|000000000|
- // |1 9|8|765|43210|9 6|54 2|10 |87 54 0|
- // |---|-|---|-----|----|----|---|---------|
- // |111|T|110| op3 | Rn | |101| |
- // 111 0 110 01001 0011 0000 101 000000011 - ec930a03
- if (op3 == 9 || op3 == 0xD) { // VLDM
- // 1110 110 PUDW1 nnnn dddd 101S iiii iiii
+
+ if (coproc == 10 || coproc == 11) { // 101x
+ if (op3 < 0x20 && (op3 >> 1) != 2) { // 0xxxxx and not 00010x
+ // extension load/store instructions
+ int op = op3 & 0x1f;
uint32_t P = (instr >> 24) & 1;
uint32_t U = (instr >> 23) & 1;
uint32_t D = (instr >> 22) & 1;
@@ -541,20 +628,49 @@ size_t DisassemblerArm::DumpThumb32(std::ostream& os, const uint8_t* instr_ptr)
uint32_t Vd = (instr >> 12) & 0xF;
uint32_t imm8 = instr & 0xFF;
uint32_t d = (S == 0 ? ((Vd << 1) | D) : (Vd | (D << 4)));
- if (P == 0 && U == 0 && W == 0) {
- // TODO: 64bit transfers between ARM core and extension registers.
- } else if (P == 0 && U == 1 && Rn.r == 13) { // VPOP
- opcode << "vpop" << (S == 0 ? ".f64" : ".f32");
- args << d << " .. " << (d + imm8);
- } else if (P == 1 && W == 0) { // VLDR
- opcode << "vldr" << (S == 0 ? ".f64" : ".f32");
- args << d << ", [" << Rn << ", #" << imm8 << "]";
- } else { // VLDM
- opcode << "vldm" << (S == 0 ? ".f64" : ".f32");
- args << Rn << ", " << d << " .. " << (d + imm8);
+ ArmRegister Rd(d, 0);
+
+ if (op == 8 || op == 12 || op == 10 || op == 14 ||
+ op == 18 || op == 22) { // 01x00 or 01x10
+ // vector store multiple or vpush
+ if (P == 1 && U == 0 && W == 1 && Rn.r == 13) {
+ opcode << "vpush" << (S == 0 ? ".f64" : ".f32");
+ args << Rd << " .. " << (Rd.r + imm8);
+ } else {
+ opcode << "vstm" << (S == 0 ? ".f64" : ".f32");
+ args << Rn << ", " << Rd << " .. " << (Rd.r + imm8);
+ }
+ } else if (op == 16 || op == 20 || op == 24 || op == 28) {
+ // 1xx00
+ // vector store register
+ opcode << "vstr" << (S == 0 ? ".f64" : ".f32");
+ args << Rd << ", [" << Rn << ", #" << imm8 << "]";
+ } else if (op == 17 || op == 21 || op == 25 || op == 29) {
+ // 1xx01
+ // vector load register
+ opcode << "vldr" << (S == 0 ? ".f64" : ".f32");
+ args << Rd << ", [" << Rn << ", #" << imm8 << "]";
+ } else if (op == 9 || op == 13 || op == 11 || op == 15 ||
+ op == 19 || op == 23 ) { // 01x11 10x11
+ // vldm or vpop
+ if (P == 1 && U == 0 && W == 1 && Rn.r == 13) {
+ opcode << "vpop" << (S == 0 ? ".f64" : ".f32");
+ args << Rd << " .. " << (Rd.r + imm8);
+ } else {
+ opcode << "vldm" << (S == 0 ? ".f64" : ".f32");
+ args << Rn << ", " << Rd << " .. " << (Rd.r + imm8);
+ }
}
+ } else if ((op3 >> 1) == 2) { // 00010x
+ // 64 bit transfers
+ } else if ((op3 >> 4) == 2 && op4 == 0) { // 10xxxx, op = 0
+ // fp data processing
+ } else if ((op3 >> 4) == 2 && op4 == 1) { // 10xxxx, op = 1
+ // 8,16,32 bit transfers
}
- } else if ((op3 & 0x30) == 0x20 && op4 == 0) { // 10 xxxx ... 0
+ }
+
+ if ((op3 & 0x30) == 0x20 && op4 == 0) { // 10 xxxx ... 0
if ((coproc & 0xE) == 0xA) {
// VFP data-processing instructions
// |111|1|1100|0000|0000|1111|110|0|00 |0|0|0000|
@@ -1070,6 +1186,72 @@ size_t DisassemblerArm::DumpThumb32(std::ostream& os, const uint8_t* instr_ptr)
}
break;
}
+ default: // more formats
+ if ((op2 >> 4) == 2) { // 010xxxx
+ // data processing (register)
+ } else if ((op2 >> 3) == 6) { // 0110xxx
+ // Multiply, multiply accumulate, and absolute difference
+ op1 = (instr >> 20) & 0x7;
+ op2 = (instr >> 4) & 0x2;
+ ArmRegister Ra(instr, 12);
+ ArmRegister Rn(instr, 16);
+ ArmRegister Rm(instr, 0);
+ ArmRegister Rd(instr, 8);
+ switch (op1) {
+ case 0:
+ if (op2 == 0) {
+ if (Ra.r == 0xf) {
+ opcode << "mul";
+ args << Rd << ", " << Rn << ", " << Rm;
+ } else {
+ opcode << "mla";
+ args << Rd << ", " << Rn << ", " << Rm << ", " << Ra;
+ }
+ } else {
+ opcode << "mls";
+ args << Rd << ", " << Rn << ", " << Rm << ", " << Ra;
+ }
+ break;
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ break; // do these sometime
+ }
+ } else if ((op2 >> 3) == 7) { // 0111xxx
+ // Long multiply, long multiply accumulate, and divide
+ op1 = (instr >> 20) & 0x7;
+ op2 = (instr >> 4) & 0xf;
+ ArmRegister Rn(instr, 16);
+ ArmRegister Rm(instr, 0);
+ ArmRegister Rd(instr, 8);
+ ArmRegister RdHi(instr, 8);
+ ArmRegister RdLo(instr, 12);
+ switch (op1) {
+ case 0:
+ opcode << "smull";
+ args << RdLo << ", " << RdHi << ", " << Rn << ", " << Rm;
+ break;
+ case 1:
+ opcode << "sdiv";
+ args << Rd << ", " << Rn << ", " << Rm;
+ break;
+ case 2:
+ opcode << "umull";
+ args << RdLo << ", " << RdHi << ", " << Rn << ", " << Rm;
+ break;
+ case 3:
+ opcode << "udiv";
+ args << Rd << ", " << Rn << ", " << Rm;
+ break;
+ case 4:
+ case 5:
+ case 6:
+ break; // TODO: when we generate these...
+ }
+ }
}
default:
break;