13a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers/*
23a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers * Copyright (C) 2012 The Android Open Source Project
33a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers *
43a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers * Licensed under the Apache License, Version 2.0 (the "License");
53a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers * you may not use this file except in compliance with the License.
63a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers * You may obtain a copy of the License at
73a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers *
83a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers *      http://www.apache.org/licenses/LICENSE-2.0
93a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers *
103a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers * Unless required by applicable law or agreed to in writing, software
113a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers * distributed under the License is distributed on an "AS IS" BASIS,
123a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers * See the License for the specific language governing permissions and
143a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers * limitations under the License.
153a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers */
163a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
173a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers#include "disassembler_arm.h"
183a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
19ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers#include <inttypes.h>
20ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers
21cf7f19135f0e273f7b0136315633c2abfc715343Ian Rogers#include <ostream>
22c7dd295a4e0cc1d15c0c96088e55a85389bade74Ian Rogers#include <sstream>
233a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
2455d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko#include "arch/arm/registers_arm.h"
252a5c4681ba19411c1cb22e9a7ab446dab910af1cAndreas Gampe#include "base/bit_utils.h"
2607ed66b5ae659c452cbe1ab20c3dbf1d6f546461Elliott Hughes#include "base/logging.h"
27e222ee0b794f941af4fb1b32fb8224e32942ea7bElliott Hughes#include "base/stringprintf.h"
2828fa76d17d741238da86dbdb47f721ae97c9eac8Elliott Hughes#include "thread.h"
290f3c55331439970e01af67f80ac117c473bc04cfElliott Hughes
303a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogersnamespace art {
313a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogersnamespace arm {
323a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
33b23a7729cf7855fa05345d03a4d84111d5ec7172Ian Rogerssize_t DisassemblerArm::Dump(std::ostream& os, const uint8_t* begin) {
34b23a7729cf7855fa05345d03a4d84111d5ec7172Ian Rogers  if ((reinterpret_cast<intptr_t>(begin) & 1) == 0) {
35b23a7729cf7855fa05345d03a4d84111d5ec7172Ian Rogers    DumpArm(os, begin);
36b23a7729cf7855fa05345d03a4d84111d5ec7172Ian Rogers    return 4;
37b23a7729cf7855fa05345d03a4d84111d5ec7172Ian Rogers  } else {
38b23a7729cf7855fa05345d03a4d84111d5ec7172Ian Rogers    // remove thumb specifier bits
39b23a7729cf7855fa05345d03a4d84111d5ec7172Ian Rogers    begin = reinterpret_cast<const uint8_t*>(reinterpret_cast<uintptr_t>(begin) & ~1);
40b23a7729cf7855fa05345d03a4d84111d5ec7172Ian Rogers    return DumpThumb16(os, begin);
41b23a7729cf7855fa05345d03a4d84111d5ec7172Ian Rogers  }
42b23a7729cf7855fa05345d03a4d84111d5ec7172Ian Rogers}
43b23a7729cf7855fa05345d03a4d84111d5ec7172Ian Rogers
443a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogersvoid DisassemblerArm::Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end) {
453a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  if ((reinterpret_cast<intptr_t>(begin) & 1) == 0) {
463a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    for (const uint8_t* cur = begin; cur < end; cur += 4) {
473a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      DumpArm(os, cur);
483a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    }
493a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  } else {
503a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    // remove thumb specifier bits
513a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    begin = reinterpret_cast<const uint8_t*>(reinterpret_cast<uintptr_t>(begin) & ~1);
523a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    end = reinterpret_cast<const uint8_t*>(reinterpret_cast<uintptr_t>(end) & ~1);
533a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    for (const uint8_t* cur = begin; cur < end;) {
543a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      cur += DumpThumb16(os, cur);
553a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    }
563a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  }
573a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers}
583a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
5977405796564c6c1353807cda18b28678a719bd68Elliott Hughesstatic const char* kConditionCodeNames[] = {
60cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes  "eq",  // 0000 - equal
61cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes  "ne",  // 0001 - not-equal
62cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes  "cs",  // 0010 - carry-set, greater than, equal or unordered
63cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes  "cc",  // 0011 - carry-clear, less than
64cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes  "mi",  // 0100 - minus, negative
65cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes  "pl",  // 0101 - plus, positive or zero
66cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes  "vs",  // 0110 - overflow
67cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes  "vc",  // 0111 - no overflow
68cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes  "hi",  // 1000 - unsigned higher
69cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes  "ls",  // 1001 - unsigned lower or same
70cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes  "ge",  // 1010 - signed greater than or equal
71cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes  "lt",  // 1011 - signed less than
72cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes  "gt",  // 1100 - signed greater than
73cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes  "le",  // 1101 - signed less than or equal
74cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes  "",    // 1110 - always
75cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes  "nv",  // 1111 - never (mostly obsolete, but might be a clue that we're mistranslating)
7640627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers};
7740627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers
7840627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogersvoid DisassemblerArm::DumpCond(std::ostream& os, uint32_t cond) {
7940627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers  if (cond < 15) {
8077405796564c6c1353807cda18b28678a719bd68Elliott Hughes    os << kConditionCodeNames[cond];
8140627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers  } else {
8240627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers    os << "Unexpected condition: " << cond;
8340627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers  }
8440627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers}
8540627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers
86b122a4bbed34ab22b4c1541ee25e5cf22f12a926Ian Rogersvoid DisassemblerArm::DumpMemoryDomain(std::ostream& os, uint32_t domain) {
87b122a4bbed34ab22b4c1541ee25e5cf22f12a926Ian Rogers  switch (domain) {
88c8ccf68b805c92674545f63e0341ba47e8d9701cAndreas Gampe    case 15U /* 0b1111 */: os << "sy"; break;
89c8ccf68b805c92674545f63e0341ba47e8d9701cAndreas Gampe    case 14U /* 0b1110 */: os << "st"; break;
90c8ccf68b805c92674545f63e0341ba47e8d9701cAndreas Gampe    case 11U /* 0b1011 */: os << "ish"; break;
91c8ccf68b805c92674545f63e0341ba47e8d9701cAndreas Gampe    case 10U /* 0b1010 */: os << "ishst"; break;
92c8ccf68b805c92674545f63e0341ba47e8d9701cAndreas Gampe    case  7U /* 0b0111 */: os << "nsh"; break;
93c8ccf68b805c92674545f63e0341ba47e8d9701cAndreas Gampe    case  6U /* 0b0110 */: os << "nshst"; break;
94c8ccf68b805c92674545f63e0341ba47e8d9701cAndreas Gampe    case  3U /* 0b0011 */: os << "osh"; break;
95c8ccf68b805c92674545f63e0341ba47e8d9701cAndreas Gampe    case  2U /* 0b0010 */: os << "oshst"; break;
96b122a4bbed34ab22b4c1541ee25e5cf22f12a926Ian Rogers  }
97b122a4bbed34ab22b4c1541ee25e5cf22f12a926Ian Rogers}
98b122a4bbed34ab22b4c1541ee25e5cf22f12a926Ian Rogers
9977405796564c6c1353807cda18b28678a719bd68Elliott Hughesvoid DisassemblerArm::DumpBranchTarget(std::ostream& os, const uint8_t* instr_ptr, int32_t imm32) {
1002cbaccb67e22c0b313a9785bfc65bcb4b25d0676Brian Carlstrom  os << StringPrintf("%+d (", imm32) << FormatInstructionPointer(instr_ptr + imm32) << ")";
10177405796564c6c1353807cda18b28678a719bd68Elliott Hughes}
10277405796564c6c1353807cda18b28678a719bd68Elliott Hughes
10377405796564c6c1353807cda18b28678a719bd68Elliott Hughesstatic uint32_t ReadU16(const uint8_t* ptr) {
10477405796564c6c1353807cda18b28678a719bd68Elliott Hughes  return ptr[0] | (ptr[1] << 8);
10577405796564c6c1353807cda18b28678a719bd68Elliott Hughes}
10677405796564c6c1353807cda18b28678a719bd68Elliott Hughes
10777405796564c6c1353807cda18b28678a719bd68Elliott Hughesstatic uint32_t ReadU32(const uint8_t* ptr) {
10877405796564c6c1353807cda18b28678a719bd68Elliott Hughes  return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
10977405796564c6c1353807cda18b28678a719bd68Elliott Hughes}
11077405796564c6c1353807cda18b28678a719bd68Elliott Hughes
11177405796564c6c1353807cda18b28678a719bd68Elliott Hughesstatic const char* kDataProcessingOperations[] = {
112cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes  "and", "eor", "sub", "rsb", "add", "adc", "sbc", "rsc",
113cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes  "tst", "teq", "cmp", "cmn", "orr", "mov", "bic", "mvn",
11477405796564c6c1353807cda18b28678a719bd68Elliott Hughes};
11577405796564c6c1353807cda18b28678a719bd68Elliott Hughes
116ad03ef509d5145d74752a0b3f5c87d99db225786Ian Rogersstatic const char* kThumbDataProcessingOperations[] = {
117ad03ef509d5145d74752a0b3f5c87d99db225786Ian Rogers  "and", "eor", "lsl", "lsr", "asr", "adc", "sbc", "ror",
118ad03ef509d5145d74752a0b3f5c87d99db225786Ian Rogers  "tst", "rsb", "cmp", "cmn", "orr", "mul", "bic", "mvn",
119ad03ef509d5145d74752a0b3f5c87d99db225786Ian Rogers};
120ad03ef509d5145d74752a0b3f5c87d99db225786Ian Rogers
121c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Markostatic const char* const kThumb2ShiftOperations[] = {
122c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko    "lsl", "lsr", "asr", "ror"
123c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko};
124c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko
125a8b4caf7526b6b66a8ae0826bd52c39c66e3c714Vladimir Markostatic const char* kThumbReverseOperations[] = {
126a8b4caf7526b6b66a8ae0826bd52c39c66e3c714Vladimir Marko    "rev", "rev16", "rbit", "revsh"
127a8b4caf7526b6b66a8ae0826bd52c39c66e3c714Vladimir Marko};
128a8b4caf7526b6b66a8ae0826bd52c39c66e3c714Vladimir Marko
12977405796564c6c1353807cda18b28678a719bd68Elliott Hughesstruct ArmRegister {
130277ccbd200ea43590dfc06a93ae184a765327ad0Andreas Gampe  explicit ArmRegister(uint32_t r_in) : r(r_in) { CHECK_LE(r_in, 15U); }
131277ccbd200ea43590dfc06a93ae184a765327ad0Andreas Gampe  ArmRegister(uint32_t instruction, uint32_t at_bit) : r((instruction >> at_bit) & 0xf) {
132277ccbd200ea43590dfc06a93ae184a765327ad0Andreas Gampe    CHECK_LE(r, 15U);
133277ccbd200ea43590dfc06a93ae184a765327ad0Andreas Gampe  }
13477405796564c6c1353807cda18b28678a719bd68Elliott Hughes  uint32_t r;
13577405796564c6c1353807cda18b28678a719bd68Elliott Hughes};
13677405796564c6c1353807cda18b28678a719bd68Elliott Hughesstd::ostream& operator<<(std::ostream& os, const ArmRegister& r) {
13777405796564c6c1353807cda18b28678a719bd68Elliott Hughes  if (r.r == 13) {
138cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes    os << "sp";
13977405796564c6c1353807cda18b28678a719bd68Elliott Hughes  } else if (r.r == 14) {
140cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes    os << "lr";
14177405796564c6c1353807cda18b28678a719bd68Elliott Hughes  } else if (r.r == 15) {
142cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes    os << "pc";
14377405796564c6c1353807cda18b28678a719bd68Elliott Hughes  } else {
144cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes    os << "r" << r.r;
14577405796564c6c1353807cda18b28678a719bd68Elliott Hughes  }
14677405796564c6c1353807cda18b28678a719bd68Elliott Hughes  return os;
14777405796564c6c1353807cda18b28678a719bd68Elliott Hughes}
14877405796564c6c1353807cda18b28678a719bd68Elliott Hughes
149630e77d4648093ce9870c7558d78edea24eab06dElliott Hughesstruct ThumbRegister : ArmRegister {
150630e77d4648093ce9870c7558d78edea24eab06dElliott Hughes  ThumbRegister(uint16_t instruction, uint16_t at_bit) : ArmRegister((instruction >> at_bit) & 0x7) {}
15177405796564c6c1353807cda18b28678a719bd68Elliott Hughes};
15277405796564c6c1353807cda18b28678a719bd68Elliott Hughes
15355d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Markostruct RmLslImm2 {
15455d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko  explicit RmLslImm2(uint32_t instr) : imm2((instr >> 4) & 0x3), rm(instr & 0xf) {}
15555d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko  uint32_t imm2;
15677405796564c6c1353807cda18b28678a719bd68Elliott Hughes  ArmRegister rm;
15777405796564c6c1353807cda18b28678a719bd68Elliott Hughes};
15855d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Markostd::ostream& operator<<(std::ostream& os, const RmLslImm2& r) {
15977405796564c6c1353807cda18b28678a719bd68Elliott Hughes  os << r.rm;
16055d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko  if (r.imm2 != 0) {
16155d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko    os << ", lsl #" << r.imm2;
16277405796564c6c1353807cda18b28678a719bd68Elliott Hughes  }
16377405796564c6c1353807cda18b28678a719bd68Elliott Hughes  return os;
16477405796564c6c1353807cda18b28678a719bd68Elliott Hughes}
16577405796564c6c1353807cda18b28678a719bd68Elliott Hughes
1661ca98499b837491f2519ca7d7d42354a0dbd45a2Elliott Hughesstruct ShiftedImmediate {
167748474146da0c6484fa3dca0a700f612d47550c3Elliott Hughes  explicit ShiftedImmediate(uint32_t instruction) {
1683d71d0799748aac23ce5935d61b909bec6e96461Elliott Hughes    uint32_t rotate = ((instruction >> 8) & 0xf);
1693d71d0799748aac23ce5935d61b909bec6e96461Elliott Hughes    uint32_t imm = (instruction & 0xff);
1703d71d0799748aac23ce5935d61b909bec6e96461Elliott Hughes    value = (imm >> (2 * rotate)) | (imm << (32 - (2 * rotate)));
1713d71d0799748aac23ce5935d61b909bec6e96461Elliott Hughes  }
1723d71d0799748aac23ce5935d61b909bec6e96461Elliott Hughes  uint32_t value;
17377405796564c6c1353807cda18b28678a719bd68Elliott Hughes};
1741ca98499b837491f2519ca7d7d42354a0dbd45a2Elliott Hughesstd::ostream& operator<<(std::ostream& os, const ShiftedImmediate& rhs) {
1753d71d0799748aac23ce5935d61b909bec6e96461Elliott Hughes  os << "#" << rhs.value;
17677405796564c6c1353807cda18b28678a719bd68Elliott Hughes  return os;
17777405796564c6c1353807cda18b28678a719bd68Elliott Hughes}
17877405796564c6c1353807cda18b28678a719bd68Elliott Hughes
17977405796564c6c1353807cda18b28678a719bd68Elliott Hughesstruct RegisterList {
180748474146da0c6484fa3dca0a700f612d47550c3Elliott Hughes  explicit RegisterList(uint32_t instruction) : register_list(instruction & 0xffff) {}
18177405796564c6c1353807cda18b28678a719bd68Elliott Hughes  uint32_t register_list;
18277405796564c6c1353807cda18b28678a719bd68Elliott Hughes};
18377405796564c6c1353807cda18b28678a719bd68Elliott Hughesstd::ostream& operator<<(std::ostream& os, const RegisterList& rhs) {
18477405796564c6c1353807cda18b28678a719bd68Elliott Hughes  if (rhs.register_list == 0) {
1853a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    os << "<no register list?>";
18677405796564c6c1353807cda18b28678a719bd68Elliott Hughes    return os;
1873a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  }
188630e77d4648093ce9870c7558d78edea24eab06dElliott Hughes  os << "{";
1893a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  bool first = true;
1903a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  for (size_t i = 0; i < 16; i++) {
19177405796564c6c1353807cda18b28678a719bd68Elliott Hughes    if ((rhs.register_list & (1 << i)) != 0) {
1923a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      if (first) {
1933a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        first = false;
1943a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      } else {
1953a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        os << ", ";
1963a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      }
19777405796564c6c1353807cda18b28678a719bd68Elliott Hughes      os << ArmRegister(i);
1983a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    }
1993a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  }
2003a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  os << "}";
20177405796564c6c1353807cda18b28678a719bd68Elliott Hughes  return os;
20240627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers}
2033a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
204dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Markostruct FpRegister {
2053887c468d731420e929e6ad3acf190d5431e94fcRoland Levillain  FpRegister(uint32_t instr, uint16_t at_bit, uint16_t extra_at_bit) {
206dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko    size = (instr >> 8) & 1;
207dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko    uint32_t Vn = (instr >> at_bit) & 0xF;
208dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko    uint32_t N = (instr >> extra_at_bit) & 1;
209dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko    r = (size != 0 ? ((N << 4) | Vn) : ((Vn << 1) | N));
210dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko  }
2113887c468d731420e929e6ad3acf190d5431e94fcRoland Levillain  FpRegister(uint32_t instr, uint16_t at_bit, uint16_t extra_at_bit, uint32_t forced_size) {
212e19649a91702234f9aa9941d76da447a1e0dcc2aZheng Xu    size = forced_size;
213e19649a91702234f9aa9941d76da447a1e0dcc2aZheng Xu    uint32_t Vn = (instr >> at_bit) & 0xF;
214e19649a91702234f9aa9941d76da447a1e0dcc2aZheng Xu    uint32_t N = (instr >> extra_at_bit) & 1;
215e19649a91702234f9aa9941d76da447a1e0dcc2aZheng Xu    r = (size != 0 ? ((N << 4) | Vn) : ((Vn << 1) | N));
216e19649a91702234f9aa9941d76da447a1e0dcc2aZheng Xu  }
217dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko  FpRegister(const FpRegister& other, uint32_t offset)
218dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko      : size(other.size), r(other.r + offset) {}
219dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko
220dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko  uint32_t size;  // 0 = f32, 1 = f64
221dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko  uint32_t r;
222dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko};
223dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Markostd::ostream& operator<<(std::ostream& os, const FpRegister& rhs) {
224dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko  return os << ((rhs.size != 0) ? "d" : "s") << rhs.r;
225dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko}
226dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko
227dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Markostruct FpRegisterRange {
228dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko  explicit FpRegisterRange(uint32_t instr)
229dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko      : first(instr, 12, 22), imm8(instr & 0xFF) {}
230dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko  FpRegister first;
231dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko  uint32_t imm8;
232dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko};
233dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Markostd::ostream& operator<<(std::ostream& os, const FpRegisterRange& rhs) {
234dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko  os << "{" << rhs.first;
235dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko  int count = (rhs.first.size != 0 ? ((rhs.imm8 + 1u) >> 1) : rhs.imm8);
236dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko  if (count > 1) {
237dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko    os << "-" << FpRegister(rhs.first, count - 1);
238dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko  }
239dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko  if (rhs.imm8 == 0) {
240dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko    os << " (EMPTY)";
241dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko  } else if (rhs.first.size != 0 && (rhs.imm8 & 1) != 0) {
242dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko    os << rhs.first << " (HALF)";
243dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko  }
244dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko  os << "}";
245dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko  return os;
246dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko}
247dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko
2483a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogersvoid DisassemblerArm::DumpArm(std::ostream& os, const uint8_t* instr_ptr) {
24977405796564c6c1353807cda18b28678a719bd68Elliott Hughes  uint32_t instruction = ReadU32(instr_ptr);
25077405796564c6c1353807cda18b28678a719bd68Elliott Hughes  uint32_t cond = (instruction >> 28) & 0xf;
25177405796564c6c1353807cda18b28678a719bd68Elliott Hughes  uint32_t op1 = (instruction >> 25) & 0x7;
2523d71d0799748aac23ce5935d61b909bec6e96461Elliott Hughes  std::string opcode;
2533d71d0799748aac23ce5935d61b909bec6e96461Elliott Hughes  std::string suffixes;
254cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes  std::ostringstream args;
25577405796564c6c1353807cda18b28678a719bd68Elliott Hughes  switch (op1) {
25677405796564c6c1353807cda18b28678a719bd68Elliott Hughes    case 0:
2577934ac288acfb2552bb0b06ec1f61e5820d924a4Brian Carlstrom    case 1:  // Data processing instructions.
25877405796564c6c1353807cda18b28678a719bd68Elliott Hughes      {
2597934ac288acfb2552bb0b06ec1f61e5820d924a4Brian Carlstrom        if ((instruction & 0x0ff000f0) == 0x01200070) {  // BKPT
2603d71d0799748aac23ce5935d61b909bec6e96461Elliott Hughes          opcode = "bkpt";
2613d71d0799748aac23ce5935d61b909bec6e96461Elliott Hughes          uint32_t imm12 = (instruction >> 8) & 0xfff;
2623d71d0799748aac23ce5935d61b909bec6e96461Elliott Hughes          uint32_t imm4 = (instruction & 0xf);
2633d71d0799748aac23ce5935d61b909bec6e96461Elliott Hughes          args << '#' << ((imm12 << 4) | imm4);
2643d71d0799748aac23ce5935d61b909bec6e96461Elliott Hughes          break;
2653d71d0799748aac23ce5935d61b909bec6e96461Elliott Hughes        }
2667934ac288acfb2552bb0b06ec1f61e5820d924a4Brian Carlstrom        if ((instruction & 0x0fffffd0) == 0x012fff10) {  // BX and BLX (register)
2673d71d0799748aac23ce5935d61b909bec6e96461Elliott Hughes          opcode = (((instruction >> 5) & 1) ? "blx" : "bx");
268cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes          args << ArmRegister(instruction & 0xf);
26977405796564c6c1353807cda18b28678a719bd68Elliott Hughes          break;
27077405796564c6c1353807cda18b28678a719bd68Elliott Hughes        }
27177405796564c6c1353807cda18b28678a719bd68Elliott Hughes        bool i = (instruction & (1 << 25)) != 0;
27277405796564c6c1353807cda18b28678a719bd68Elliott Hughes        bool s = (instruction & (1 << 20)) != 0;
2733d71d0799748aac23ce5935d61b909bec6e96461Elliott Hughes        uint32_t op = (instruction >> 21) & 0xf;
2743d71d0799748aac23ce5935d61b909bec6e96461Elliott Hughes        opcode = kDataProcessingOperations[op];
2757934ac288acfb2552bb0b06ec1f61e5820d924a4Brian Carlstrom        bool implicit_s = ((op & ~3) == 8);  // TST, TEQ, CMP, and CMN.
276c8ccf68b805c92674545f63e0341ba47e8d9701cAndreas Gampe        bool is_mov = op == 13U /* 0b1101 */ || op == 15U /* 0b1111 */;
27720dfc797dc631bf8d655dcf123f46f13332d3074Dave Allison        if (is_mov) {
27820dfc797dc631bf8d655dcf123f46f13332d3074Dave Allison          // Show only Rd and Rm.
2793d71d0799748aac23ce5935d61b909bec6e96461Elliott Hughes          if (s) {
28020dfc797dc631bf8d655dcf123f46f13332d3074Dave Allison             suffixes += 's';
28120dfc797dc631bf8d655dcf123f46f13332d3074Dave Allison           }
28220dfc797dc631bf8d655dcf123f46f13332d3074Dave Allison           args << ArmRegister(instruction, 12) << ", ";
28320dfc797dc631bf8d655dcf123f46f13332d3074Dave Allison           if (i) {
28420dfc797dc631bf8d655dcf123f46f13332d3074Dave Allison              args << ShiftedImmediate(instruction);
28520dfc797dc631bf8d655dcf123f46f13332d3074Dave Allison            } else {
28620dfc797dc631bf8d655dcf123f46f13332d3074Dave Allison              // TODO: Shifted register.
28720dfc797dc631bf8d655dcf123f46f13332d3074Dave Allison              args << ArmRegister(instruction, 16) << ", " << ArmRegister(instruction, 0);
28820dfc797dc631bf8d655dcf123f46f13332d3074Dave Allison            }
28977405796564c6c1353807cda18b28678a719bd68Elliott Hughes        } else {
29020dfc797dc631bf8d655dcf123f46f13332d3074Dave Allison          if (implicit_s) {
29120dfc797dc631bf8d655dcf123f46f13332d3074Dave Allison            // Rd is unused (and not shown), and we don't show the 's' suffix either.
29220dfc797dc631bf8d655dcf123f46f13332d3074Dave Allison          } else {
29320dfc797dc631bf8d655dcf123f46f13332d3074Dave Allison            if (s) {
29420dfc797dc631bf8d655dcf123f46f13332d3074Dave Allison              suffixes += 's';
29520dfc797dc631bf8d655dcf123f46f13332d3074Dave Allison            }
29620dfc797dc631bf8d655dcf123f46f13332d3074Dave Allison            args << ArmRegister(instruction, 12) << ", ";
29720dfc797dc631bf8d655dcf123f46f13332d3074Dave Allison          }
29820dfc797dc631bf8d655dcf123f46f13332d3074Dave Allison          if (i) {
29920dfc797dc631bf8d655dcf123f46f13332d3074Dave Allison            args << ArmRegister(instruction, 16) << ", " << ShiftedImmediate(instruction);
30020dfc797dc631bf8d655dcf123f46f13332d3074Dave Allison          } else {
30120dfc797dc631bf8d655dcf123f46f13332d3074Dave Allison            // TODO: Shifted register.
30220dfc797dc631bf8d655dcf123f46f13332d3074Dave Allison            args << ArmRegister(instruction, 16) << ", " << ArmRegister(instruction, 0);
30320dfc797dc631bf8d655dcf123f46f13332d3074Dave Allison          }
30477405796564c6c1353807cda18b28678a719bd68Elliott Hughes        }
30577405796564c6c1353807cda18b28678a719bd68Elliott Hughes      }
30677405796564c6c1353807cda18b28678a719bd68Elliott Hughes      break;
3077934ac288acfb2552bb0b06ec1f61e5820d924a4Brian Carlstrom    case 2:  // Load/store word and unsigned byte.
30877405796564c6c1353807cda18b28678a719bd68Elliott Hughes      {
30977405796564c6c1353807cda18b28678a719bd68Elliott Hughes        bool p = (instruction & (1 << 24)) != 0;
31077405796564c6c1353807cda18b28678a719bd68Elliott Hughes        bool b = (instruction & (1 << 22)) != 0;
31177405796564c6c1353807cda18b28678a719bd68Elliott Hughes        bool w = (instruction & (1 << 21)) != 0;
31277405796564c6c1353807cda18b28678a719bd68Elliott Hughes        bool l = (instruction & (1 << 20)) != 0;
3133d71d0799748aac23ce5935d61b909bec6e96461Elliott Hughes        opcode = StringPrintf("%s%s", (l ? "ldr" : "str"), (b ? "b" : ""));
314630e77d4648093ce9870c7558d78edea24eab06dElliott Hughes        args << ArmRegister(instruction, 12) << ", ";
315630e77d4648093ce9870c7558d78edea24eab06dElliott Hughes        ArmRegister rn(instruction, 16);
316630e77d4648093ce9870c7558d78edea24eab06dElliott Hughes        if (rn.r == 0xf) {
31777405796564c6c1353807cda18b28678a719bd68Elliott Hughes          UNIMPLEMENTED(FATAL) << "literals";
31877405796564c6c1353807cda18b28678a719bd68Elliott Hughes        } else {
31977405796564c6c1353807cda18b28678a719bd68Elliott Hughes          bool wback = !p || w;
3201ca98499b837491f2519ca7d7d42354a0dbd45a2Elliott Hughes          uint32_t offset = (instruction & 0xfff);
32177405796564c6c1353807cda18b28678a719bd68Elliott Hughes          if (p && !wback) {
3221ca98499b837491f2519ca7d7d42354a0dbd45a2Elliott Hughes            args << "[" << rn << ", #" << offset << "]";
32377405796564c6c1353807cda18b28678a719bd68Elliott Hughes          } else if (p && wback) {
3241ca98499b837491f2519ca7d7d42354a0dbd45a2Elliott Hughes            args << "[" << rn << ", #" << offset << "]!";
32577405796564c6c1353807cda18b28678a719bd68Elliott Hughes          } else if (!p && wback) {
3261ca98499b837491f2519ca7d7d42354a0dbd45a2Elliott Hughes            args << "[" << rn << "], #" << offset;
32777405796564c6c1353807cda18b28678a719bd68Elliott Hughes          } else {
32877405796564c6c1353807cda18b28678a719bd68Elliott Hughes            LOG(FATAL) << p << " " << w;
32977405796564c6c1353807cda18b28678a719bd68Elliott Hughes          }
3303d71d0799748aac23ce5935d61b909bec6e96461Elliott Hughes          if (rn.r == 9) {
3313d71d0799748aac23ce5935d61b909bec6e96461Elliott Hughes            args << "  ; ";
332dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogers            Thread::DumpThreadOffset<4>(args, offset);
3333d71d0799748aac23ce5935d61b909bec6e96461Elliott Hughes          }
33477405796564c6c1353807cda18b28678a719bd68Elliott Hughes        }
33577405796564c6c1353807cda18b28678a719bd68Elliott Hughes      }
33677405796564c6c1353807cda18b28678a719bd68Elliott Hughes      break;
3377934ac288acfb2552bb0b06ec1f61e5820d924a4Brian Carlstrom    case 4:  // Load/store multiple.
33877405796564c6c1353807cda18b28678a719bd68Elliott Hughes      {
33977405796564c6c1353807cda18b28678a719bd68Elliott Hughes        bool p = (instruction & (1 << 24)) != 0;
34077405796564c6c1353807cda18b28678a719bd68Elliott Hughes        bool u = (instruction & (1 << 23)) != 0;
34177405796564c6c1353807cda18b28678a719bd68Elliott Hughes        bool w = (instruction & (1 << 21)) != 0;
34277405796564c6c1353807cda18b28678a719bd68Elliott Hughes        bool l = (instruction & (1 << 20)) != 0;
3433d71d0799748aac23ce5935d61b909bec6e96461Elliott Hughes        opcode = StringPrintf("%s%c%c", (l ? "ldm" : "stm"), (u ? 'i' : 'd'), (p ? 'b' : 'a'));
344630e77d4648093ce9870c7558d78edea24eab06dElliott Hughes        args << ArmRegister(instruction, 16) << (w ? "!" : "") << ", " << RegisterList(instruction);
34577405796564c6c1353807cda18b28678a719bd68Elliott Hughes      }
34677405796564c6c1353807cda18b28678a719bd68Elliott Hughes      break;
3477934ac288acfb2552bb0b06ec1f61e5820d924a4Brian Carlstrom    case 5:  // Branch/branch with link.
3483d71d0799748aac23ce5935d61b909bec6e96461Elliott Hughes      {
3493d71d0799748aac23ce5935d61b909bec6e96461Elliott Hughes        bool bl = (instruction & (1 << 24)) != 0;
3503d71d0799748aac23ce5935d61b909bec6e96461Elliott Hughes        opcode = (bl ? "bl" : "b");
351d86261ed72e4fb294f602e1831306612291b0f24Elliott Hughes        int32_t imm26 = (instruction & 0xffffff) << 2;
3527934ac288acfb2552bb0b06ec1f61e5820d924a4Brian Carlstrom        int32_t imm32 = (imm26 << 6) >> 6;  // Sign extend.
3533d71d0799748aac23ce5935d61b909bec6e96461Elliott Hughes        DumpBranchTarget(args, instr_ptr + 8, imm32);
3543d71d0799748aac23ce5935d61b909bec6e96461Elliott Hughes      }
3553d71d0799748aac23ce5935d61b909bec6e96461Elliott Hughes      break;
35677405796564c6c1353807cda18b28678a719bd68Elliott Hughes    default:
3573d71d0799748aac23ce5935d61b909bec6e96461Elliott Hughes      opcode = "???";
35877405796564c6c1353807cda18b28678a719bd68Elliott Hughes      break;
35977405796564c6c1353807cda18b28678a719bd68Elliott Hughes    }
3603d71d0799748aac23ce5935d61b909bec6e96461Elliott Hughes    opcode += kConditionCodeNames[cond];
3613d71d0799748aac23ce5935d61b909bec6e96461Elliott Hughes    opcode += suffixes;
362cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes    // TODO: a more complete ARM disassembler could generate wider opcodes.
3632cbaccb67e22c0b313a9785bfc65bcb4b25d0676Brian Carlstrom    os << FormatInstructionPointer(instr_ptr)
3642cbaccb67e22c0b313a9785bfc65bcb4b25d0676Brian Carlstrom       << StringPrintf(": %08x\t%-7s ", instruction, opcode.c_str())
3652cbaccb67e22c0b313a9785bfc65bcb4b25d0676Brian Carlstrom       << args.str() << '\n';
3663a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers}
3673a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
368a9650dd5e7195aec987a69a6ebbdaf33f73a6b00Ian Rogersint32_t ThumbExpand(int32_t imm12) {
369a9650dd5e7195aec987a69a6ebbdaf33f73a6b00Ian Rogers  if ((imm12 & 0xC00) == 0) {
370a9650dd5e7195aec987a69a6ebbdaf33f73a6b00Ian Rogers    switch ((imm12 >> 8) & 3) {
371a9650dd5e7195aec987a69a6ebbdaf33f73a6b00Ian Rogers      case 0:
372a9650dd5e7195aec987a69a6ebbdaf33f73a6b00Ian Rogers        return imm12 & 0xFF;
373a9650dd5e7195aec987a69a6ebbdaf33f73a6b00Ian Rogers      case 1:
374a9650dd5e7195aec987a69a6ebbdaf33f73a6b00Ian Rogers        return ((imm12 & 0xFF) << 16) | (imm12 & 0xFF);
375a9650dd5e7195aec987a69a6ebbdaf33f73a6b00Ian Rogers      case 2:
376a9650dd5e7195aec987a69a6ebbdaf33f73a6b00Ian Rogers        return ((imm12 & 0xFF) << 24) | ((imm12 & 0xFF) << 8);
377a9650dd5e7195aec987a69a6ebbdaf33f73a6b00Ian Rogers      default:  // 3
378a9650dd5e7195aec987a69a6ebbdaf33f73a6b00Ian Rogers        return ((imm12 & 0xFF) << 24) | ((imm12 & 0xFF) << 16) | ((imm12 & 0xFF) << 8) |
379a9650dd5e7195aec987a69a6ebbdaf33f73a6b00Ian Rogers            (imm12 & 0xFF);
380a9650dd5e7195aec987a69a6ebbdaf33f73a6b00Ian Rogers    }
381a9650dd5e7195aec987a69a6ebbdaf33f73a6b00Ian Rogers  } else {
382a9650dd5e7195aec987a69a6ebbdaf33f73a6b00Ian Rogers    uint32_t val = 0x80 | (imm12 & 0x7F);
383a9650dd5e7195aec987a69a6ebbdaf33f73a6b00Ian Rogers    int32_t rotate = (imm12 >> 7) & 0x1F;
384a9650dd5e7195aec987a69a6ebbdaf33f73a6b00Ian Rogers    return (val >> rotate) | (val << (32 - rotate));
385a9650dd5e7195aec987a69a6ebbdaf33f73a6b00Ian Rogers  }
386a9650dd5e7195aec987a69a6ebbdaf33f73a6b00Ian Rogers}
387a9650dd5e7195aec987a69a6ebbdaf33f73a6b00Ian Rogers
388c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Markouint32_t VFPExpand32(uint32_t imm8) {
389c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko  CHECK_EQ(imm8 & 0xffu, imm8);
390c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko  uint32_t bit_a = (imm8 >> 7) & 1;
391c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko  uint32_t bit_b = (imm8 >> 6) & 1;
392c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko  uint32_t slice = imm8 & 0x3f;
393c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko  return (bit_a << 31) | ((1 << 30) - (bit_b << 25)) | (slice << 19);
394c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko}
395c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko
396277ccbd200ea43590dfc06a93ae184a765327ad0Andreas Gampestatic uint64_t VFPExpand64(uint32_t imm8) {
397c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko  CHECK_EQ(imm8 & 0xffu, imm8);
398c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko  uint64_t bit_a = (imm8 >> 7) & 1;
399c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko  uint64_t bit_b = (imm8 >> 6) & 1;
400c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko  uint64_t slice = imm8 & 0x3f;
40155d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko  return (bit_a << 63) | ((UINT64_C(1) << 62) - (bit_b << 54)) | (slice << 48);
40255d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko}
40355d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko
40455d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Markoenum T2LitType {
40555d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko  kT2LitInvalid,
40655d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko  kT2LitUByte,
40755d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko  kT2LitSByte,
40855d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko  kT2LitUHalf,
40955d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko  kT2LitSHalf,
41055d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko  kT2LitUWord,
41155d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko  kT2LitSWord,
41255d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko  kT2LitHexWord,
41355d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko  kT2LitULong,
41455d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko  kT2LitSLong,
41555d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko  kT2LitHexLong,
41655d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko};
41755d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Markostd::ostream& operator<<(std::ostream& os, T2LitType type) {
41855d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko  return os << static_cast<int>(type);
41955d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko}
42055d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko
421a6e95b32d499811bbb37602fc7446a5a0d05b9f8Aart Bikvoid DumpThumb2Literal(std::ostream& args,
422a6e95b32d499811bbb37602fc7446a5a0d05b9f8Aart Bik                       const uint8_t* instr_ptr,
423a6e95b32d499811bbb37602fc7446a5a0d05b9f8Aart Bik                       const uintptr_t lo_adr,
424a6e95b32d499811bbb37602fc7446a5a0d05b9f8Aart Bik                       const uintptr_t hi_adr,
425a6e95b32d499811bbb37602fc7446a5a0d05b9f8Aart Bik                       uint32_t U,
426a6e95b32d499811bbb37602fc7446a5a0d05b9f8Aart Bik                       uint32_t imm32,
42755d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko                       T2LitType type) {
42855d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko  // Literal offsets (imm32) are not required to be aligned so we may need unaligned access.
42955d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko  typedef const int16_t unaligned_int16_t __attribute__ ((aligned (1)));
43055d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko  typedef const uint16_t unaligned_uint16_t __attribute__ ((aligned (1)));
43155d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko  typedef const int32_t unaligned_int32_t __attribute__ ((aligned (1)));
43255d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko  typedef const uint32_t unaligned_uint32_t __attribute__ ((aligned (1)));
43355d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko  typedef const int64_t unaligned_int64_t __attribute__ ((aligned (1)));
43455d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko  typedef const uint64_t unaligned_uint64_t __attribute__ ((aligned (1)));
43555d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko
436a6e95b32d499811bbb37602fc7446a5a0d05b9f8Aart Bik  // Get address of literal. Bail if not within expected buffer range to
437a6e95b32d499811bbb37602fc7446a5a0d05b9f8Aart Bik  // avoid trying to fetch invalid literals (we can encounter this when
438a6e95b32d499811bbb37602fc7446a5a0d05b9f8Aart Bik  // interpreting raw data as instructions).
43955d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko  uintptr_t pc = RoundDown(reinterpret_cast<intptr_t>(instr_ptr) + 4, 4);
44055d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko  uintptr_t lit_adr = U ? pc + imm32 : pc - imm32;
441a6e95b32d499811bbb37602fc7446a5a0d05b9f8Aart Bik  if (lit_adr < lo_adr || lit_adr >= hi_adr) {
442a6e95b32d499811bbb37602fc7446a5a0d05b9f8Aart Bik    args << "  ; (?)";
443a6e95b32d499811bbb37602fc7446a5a0d05b9f8Aart Bik    return;
444a6e95b32d499811bbb37602fc7446a5a0d05b9f8Aart Bik  }
445a6e95b32d499811bbb37602fc7446a5a0d05b9f8Aart Bik
44655d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko  args << "  ; ";
44755d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko  switch (type) {
44855d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko    case kT2LitUByte:
44955d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko      args << *reinterpret_cast<const uint8_t*>(lit_adr);
45055d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko      break;
45155d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko    case kT2LitSByte:
45255d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko      args << *reinterpret_cast<const int8_t*>(lit_adr);
45355d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko      break;
45455d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko    case kT2LitUHalf:
45555d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko      args << *reinterpret_cast<const unaligned_uint16_t*>(lit_adr);
45655d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko      break;
45755d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko    case kT2LitSHalf:
45855d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko      args << *reinterpret_cast<const unaligned_int16_t*>(lit_adr);
45955d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko      break;
46055d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko    case kT2LitUWord:
46155d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko      args << *reinterpret_cast<const unaligned_uint32_t*>(lit_adr);
46255d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko      break;
46355d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko    case kT2LitSWord:
46455d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko      args << *reinterpret_cast<const unaligned_int32_t*>(lit_adr);
46555d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko      break;
46655d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko    case kT2LitHexWord:
46755d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko      args << StringPrintf("0x%08x", *reinterpret_cast<const unaligned_uint32_t*>(lit_adr));
46855d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko      break;
46955d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko    case kT2LitULong:
47055d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko      args << *reinterpret_cast<const unaligned_uint64_t*>(lit_adr);
47155d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko      break;
47255d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko    case kT2LitSLong:
47355d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko      args << *reinterpret_cast<const unaligned_int64_t*>(lit_adr);
47455d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko      break;
47555d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko    case kT2LitHexLong:
47655d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko      args << StringPrintf("0x%" PRIx64, *reinterpret_cast<unaligned_int64_t*>(lit_adr));
47755d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko      break;
47855d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko    default:
47955d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko      LOG(FATAL) << "Invalid type: " << type;
48055d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko      break;
48155d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko  }
482c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko}
483c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko
4843a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogerssize_t DisassemblerArm::DumpThumb32(std::ostream& os, const uint8_t* instr_ptr) {
4853a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  uint32_t instr = (ReadU16(instr_ptr) << 16) | ReadU16(instr_ptr + 2);
4863a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  // |111|1 1|1000000|0000|1111110000000000|
4873a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  // |5 3|2 1|0987654|3  0|5    0    5    0|
4883a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  // |---|---|-------|----|----------------|
4893a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  // |332|2 2|2222222|1111|1111110000000000|
4903a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  // |1 9|8 7|6543210|9  6|5    0    5    0|
4913a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  // |---|---|-------|----|----------------|
4923a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  // |111|op1| op2   |    |                |
4933a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  uint32_t op1 = (instr >> 27) & 3;
49477405796564c6c1353807cda18b28678a719bd68Elliott Hughes  if (op1 == 0) {
49577405796564c6c1353807cda18b28678a719bd68Elliott Hughes    return DumpThumb16(os, instr_ptr);
49677405796564c6c1353807cda18b28678a719bd68Elliott Hughes  }
49777405796564c6c1353807cda18b28678a719bd68Elliott Hughes
498a6e95b32d499811bbb37602fc7446a5a0d05b9f8Aart Bik  // Set valid address range of backing buffer.
499a6e95b32d499811bbb37602fc7446a5a0d05b9f8Aart Bik  const uintptr_t lo_adr = reinterpret_cast<intptr_t>(GetDisassemblerOptions()->base_address_);
500a6e95b32d499811bbb37602fc7446a5a0d05b9f8Aart Bik  const uintptr_t hi_adr = reinterpret_cast<intptr_t>(GetDisassemblerOptions()->end_address_);
501a6e95b32d499811bbb37602fc7446a5a0d05b9f8Aart Bik
5023a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  uint32_t op2 = (instr >> 20) & 0x7F;
503cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes  std::ostringstream opcode;
504cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes  std::ostringstream args;
5053a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  switch (op1) {
5063a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    case 0:
5073a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      break;
5083a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    case 1:
509c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers      if ((op2 & 0x64) == 0) {  // 00x x0xx
510c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers        // |111|11|10|00|0|00|0000|1111110000000000|
511c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers        // |5 3|21|09|87|6|54|3  0|5    0    5    0|
512c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers        // |---|--|--|--|-|--|----|----------------|
513c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers        // |332|22|22|22|2|22|1111|1111110000000000|
514c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers        // |1 9|87|65|43|2|10|9  6|5    0    5    0|
515c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers        // |---|--|--|--|-|--|----|----------------|
516c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers        // |111|01|00|op|0|WL| Rn |                |
517c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers        // |111|01| op2      |    |                |
518c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers        // STM - 111 01 00-01-0-W0 nnnn rrrrrrrrrrrrrrrr
519c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers        // LDM - 111 01 00-01-0-W1 nnnn rrrrrrrrrrrrrrrr
520c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers        // PUSH- 111 01 00-01-0-10 1101 0M0rrrrrrrrrrrrr
521c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers        // POP - 111 01 00-01-0-11 1101 PM0rrrrrrrrrrrrr
522c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers        uint32_t op = (instr >> 23) & 3;
523c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers        uint32_t W = (instr >> 21) & 1;
524c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers        uint32_t L = (instr >> 20) & 1;
525c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers        ArmRegister Rn(instr, 16);
526c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers        if (op == 1 || op == 2) {
527c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers          if (op == 1) {
528c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers            if (L == 0) {
529c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers              opcode << "stm";
530c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers              args << Rn << (W == 0 ? "" : "!") << ", ";
531c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers            } else {
532c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers              if (Rn.r != 13) {
533c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers                opcode << "ldm";
534630e77d4648093ce9870c7558d78edea24eab06dElliott Hughes                args << Rn << (W == 0 ? "" : "!") << ", ";
5353a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers              } else {
536c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers                opcode << "pop";
5373a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers              }
538c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers            }
539c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers          } else {
540c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers            if (L == 0) {
541c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers              if (Rn.r != 13) {
542c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers                opcode << "stmdb";
543630e77d4648093ce9870c7558d78edea24eab06dElliott Hughes                args << Rn << (W == 0 ? "" : "!") << ", ";
544c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers              } else {
545c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers                opcode << "push";
5463a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers              }
547c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers            } else {
548c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers              opcode << "ldmdb";
549c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers              args << Rn << (W == 0 ? "" : "!") << ", ";
5503a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers            }
5513a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          }
552c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers          args << RegisterList(instr);
553c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers        }
5547934ac288acfb2552bb0b06ec1f61e5820d924a4Brian Carlstrom      } else if ((op2 & 0x64) == 4) {  // 00x x1xx
5559af8940be07c83b150c6922fa341b854daf37455Ian Rogers        uint32_t op3 = (instr >> 23) & 3;
5569af8940be07c83b150c6922fa341b854daf37455Ian Rogers        uint32_t op4 = (instr >> 20) & 3;
5577934ac288acfb2552bb0b06ec1f61e5820d924a4Brian Carlstrom        // uint32_t op5 = (instr >> 4) & 0xF;
5589af8940be07c83b150c6922fa341b854daf37455Ian Rogers        ArmRegister Rn(instr, 16);
5599af8940be07c83b150c6922fa341b854daf37455Ian Rogers        ArmRegister Rt(instr, 12);
5607020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison        ArmRegister Rd(instr, 8);
5619af8940be07c83b150c6922fa341b854daf37455Ian Rogers        uint32_t imm8 = instr & 0xFF;
5627020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison        if ((op3 & 2) == 2) {     // 1x
5637020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          int W = (instr >> 21) & 1;
5647020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          int U = (instr >> 23) & 1;
5657020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          int P = (instr >> 24) & 1;
5667020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison
5677020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          if ((op4 & 1) == 1) {
5687020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison            opcode << "ldrd";
5697020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          } else {
5707020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison            opcode << "strd";
5717020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          }
5727020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          args << Rt << "," << Rd << ", [" << Rn;
5737020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          const char *sign = U ? "+" : "-";
5747020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          if (P == 0 && W == 1) {
575ad435ebd9d011eef66ef77e96b065024220c10adVladimir Marko            args << "], #" << sign << (imm8 << 2);
5767020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          } else {
577ad435ebd9d011eef66ef77e96b065024220c10adVladimir Marko            args << ", #" << sign << (imm8 << 2) << "]";
5787020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison            if (W == 1) {
5797020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison              args << "!";
5807020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison            }
5817020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          }
5827020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison        } else {                  // 0x
5837020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          switch (op4) {
5847020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison            case 0:
5857020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison              if (op3 == 0) {   // op3 is 00, op4 is 00
5867020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison                opcode << "strex";
5877020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison                args << Rd << ", " << Rt << ", [" << Rn << ", #" << (imm8 << 2) << "]";
5883e5af82ae1a2cd69b7b045ac008ac3b394d17f41Vladimir Marko                if (Rd.r == 13 || Rd.r == 15 || Rt.r == 13 || Rt.r == 15 || Rn.r == 15 ||
5893e5af82ae1a2cd69b7b045ac008ac3b394d17f41Vladimir Marko                    Rd.r == Rn.r || Rd.r == Rt.r) {
5903e5af82ae1a2cd69b7b045ac008ac3b394d17f41Vladimir Marko                  args << " (UNPREDICTABLE)";
5913e5af82ae1a2cd69b7b045ac008ac3b394d17f41Vladimir Marko                }
5927020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison              } else {          // op3 is 01, op4 is 00
5937020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison                // this is one of strexb, strexh or strexd
5947020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison                int op5 = (instr >> 4) & 0xf;
5957020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison                switch (op5) {
5967020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison                  case 4:
5977020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison                  case 5:
5983e5af82ae1a2cd69b7b045ac008ac3b394d17f41Vladimir Marko                    opcode << ((op5 == 4) ? "strexb" : "strexh");
5993e5af82ae1a2cd69b7b045ac008ac3b394d17f41Vladimir Marko                    Rd = ArmRegister(instr, 0);
6003e5af82ae1a2cd69b7b045ac008ac3b394d17f41Vladimir Marko                    args << Rd << ", " << Rt << ", [" << Rn << "]";
6013e5af82ae1a2cd69b7b045ac008ac3b394d17f41Vladimir Marko                    if (Rd.r == 13 || Rd.r == 15 || Rt.r == 13 || Rt.r == 15 || Rn.r == 15 ||
6023e5af82ae1a2cd69b7b045ac008ac3b394d17f41Vladimir Marko                        Rd.r == Rn.r || Rd.r == Rt.r || (instr & 0xf00) != 0xf00) {
6033e5af82ae1a2cd69b7b045ac008ac3b394d17f41Vladimir Marko                      args << " (UNPREDICTABLE)";
6043e5af82ae1a2cd69b7b045ac008ac3b394d17f41Vladimir Marko                    }
6057020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison                    break;
6067020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison                  case 7:
6077020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison                    opcode << "strexd";
6083e5af82ae1a2cd69b7b045ac008ac3b394d17f41Vladimir Marko                    ArmRegister Rt2 = Rd;
6093e5af82ae1a2cd69b7b045ac008ac3b394d17f41Vladimir Marko                    Rd = ArmRegister(instr, 0);
6103e5af82ae1a2cd69b7b045ac008ac3b394d17f41Vladimir Marko                    args << Rd << ", " << Rt << ", " << Rt2 << ", [" << Rn << "]";
6113e5af82ae1a2cd69b7b045ac008ac3b394d17f41Vladimir Marko                    if (Rd.r == 13 || Rd.r == 15 || Rt.r == 13 || Rt.r == 15 ||
6123e5af82ae1a2cd69b7b045ac008ac3b394d17f41Vladimir Marko                        Rt2.r == 13 || Rt2.r == 15 || Rn.r == 15 ||
6133e5af82ae1a2cd69b7b045ac008ac3b394d17f41Vladimir Marko                        Rd.r == Rn.r || Rd.r == Rt.r || Rd.r == Rt2.r) {
6143e5af82ae1a2cd69b7b045ac008ac3b394d17f41Vladimir Marko                      args << " (UNPREDICTABLE)";
6153e5af82ae1a2cd69b7b045ac008ac3b394d17f41Vladimir Marko                    }
6167020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison                    break;
6177020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison                }
6187020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison              }
6197020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison              break;
6207020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison            case 1:
6217020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison              if (op3 == 0) {   // op3 is 00, op4 is 01
6227020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison                opcode << "ldrex";
6237020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison                args << Rt << ", [" << Rn << ", #" << (imm8 << 2) << "]";
6243e5af82ae1a2cd69b7b045ac008ac3b394d17f41Vladimir Marko                if (Rt.r == 13 || Rt.r == 15 || Rn.r == 15 || (instr & 0xf00) != 0xf00) {
6253e5af82ae1a2cd69b7b045ac008ac3b394d17f41Vladimir Marko                  args << " (UNPREDICTABLE)";
6263e5af82ae1a2cd69b7b045ac008ac3b394d17f41Vladimir Marko                }
6277020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison              } else {          // op3 is 01, op4 is 01
6287020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison                // this is one of strexb, strexh or strexd
6297020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison                int op5 = (instr >> 4) & 0xf;
6307020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison                switch (op5) {
6317020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison                  case 0:
6327020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison                    opcode << "tbb";
6337020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison                    break;
6347020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison                  case 1:
6357020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison                    opcode << "tbh";
6367020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison                    break;
6377020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison                  case 4:
6387020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison                  case 5:
6393e5af82ae1a2cd69b7b045ac008ac3b394d17f41Vladimir Marko                    opcode << ((op5 == 4) ? "ldrexb" : "ldrexh");
6403e5af82ae1a2cd69b7b045ac008ac3b394d17f41Vladimir Marko                    args << Rt << ", [" << Rn << "]";
6413e5af82ae1a2cd69b7b045ac008ac3b394d17f41Vladimir Marko                    if (Rt.r == 13 || Rt.r == 15 || Rn.r == 15 || (instr & 0xf0f) != 0xf0f) {
6423e5af82ae1a2cd69b7b045ac008ac3b394d17f41Vladimir Marko                      args << " (UNPREDICTABLE)";
6433e5af82ae1a2cd69b7b045ac008ac3b394d17f41Vladimir Marko                    }
6447020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison                    break;
6457020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison                  case 7:
6467020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison                    opcode << "ldrexd";
6473e5af82ae1a2cd69b7b045ac008ac3b394d17f41Vladimir Marko                    args << Rt << ", " << Rd /* Rt2 */ << ", [" << Rn << "]";
6483e5af82ae1a2cd69b7b045ac008ac3b394d17f41Vladimir Marko                    if (Rt.r == 13 || Rt.r == 15 || Rd.r == 13 /* Rt2 */ || Rd.r == 15 /* Rt2 */ ||
6493e5af82ae1a2cd69b7b045ac008ac3b394d17f41Vladimir Marko                        Rn.r == 15 || (instr & 0x00f) != 0x00f) {
6503e5af82ae1a2cd69b7b045ac008ac3b394d17f41Vladimir Marko                      args << " (UNPREDICTABLE)";
6513e5af82ae1a2cd69b7b045ac008ac3b394d17f41Vladimir Marko                    }
6527020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison                    break;
6537020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison                }
6547020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison              }
6557020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison              break;
6567020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison            case 2:     // op3 is 0x, op4 is 10
6577020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison            case 3:   // op3 is 0x, op4 is 11
6587020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison              if (op4 == 2) {
6597020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison                opcode << "strd";
6607020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison              } else {
6617020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison                opcode << "ldrd";
6627020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison              }
6637020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison              int W = (instr >> 21) & 1;
6647020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison              int U = (instr >> 23) & 1;
6657020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison              int P = (instr >> 24) & 1;
6667020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison
6677020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison              args << Rt << "," << Rd << ", [" << Rn;
6687020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison              const char *sign = U ? "+" : "-";
6697020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison              if (P == 0 && W == 1) {
6707020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison                args << "], #" << sign << imm8;
6717020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison              } else {
6727020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison                args << ", #" << sign << imm8 << "]";
6737020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison                if (W == 1) {
6747020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison                  args << "!";
6757020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison                }
6767020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison              }
6777020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison              break;
6787020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          }
6797020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison        }
6807020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison
681c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers      } else if ((op2 & 0x60) == 0x20) {  // 01x xxxx
682c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers        // Data-processing (shifted register)
683d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz        // |111|1110|0000|0|0000|1111|1100|00|00|0000|
684d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz        // |5 3|2109|8765|4|3  0|5   |10 8|7 |5 |3  0|
685d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz        // |---|----|----|-|----|----|----|--|--|----|
686d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz        // |332|2222|2222|2|1111|1111|1100|00|00|0000|
687d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz        // |1 9|8765|4321|0|9  6|5   |10 8|7 |5 |3  0|
688d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz        // |---|----|----|-|----|----|----|--|--|----|
689d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz        // |111|0101| op3|S| Rn |imm3| Rd |i2|ty| Rm |
690c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers        uint32_t op3 = (instr >> 21) & 0xF;
691c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers        uint32_t S = (instr >> 20) & 1;
692d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz        uint32_t imm3 = ((instr >> 12) & 0x7);
693d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz        uint32_t imm2 = ((instr >> 6) & 0x3);
6947d180cb41d3104af7c85a5b808bb9f57c264c2a6Dmitriy Ivanov        uint32_t imm5 = ((imm3 << 2) | imm2);
6957d180cb41d3104af7c85a5b808bb9f57c264c2a6Dmitriy Ivanov        uint32_t shift_type = ((instr >> 4) & 0x3);
696c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers        ArmRegister Rd(instr, 8);
697d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz        ArmRegister Rn(instr, 16);
698c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers        ArmRegister Rm(instr, 0);
699c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers        switch (op3) {
700c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers          case 0x0:
701d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz            if (Rd.r != 0xF) {
702c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers              opcode << "and";
703c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers            } else {
7044a999e2424610f7a20ea0b0f25828f9205a83536Brian Carlstrom              if (S != 1U) {
7054a999e2424610f7a20ea0b0f25828f9205a83536Brian Carlstrom                opcode << "UNKNOWN TST-" << S;
7064a999e2424610f7a20ea0b0f25828f9205a83536Brian Carlstrom                break;
7074a999e2424610f7a20ea0b0f25828f9205a83536Brian Carlstrom              }
708c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers              opcode << "tst";
709c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers              S = 0;  // don't print 's'
710c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers            }
711c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers            break;
712c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers          case 0x1: opcode << "bic"; break;
713c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers          case 0x2:
714d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz            if (Rn.r != 0xF) {
715c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers              opcode << "orr";
716c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers            } else {
717d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz              // TODO: use canonical form if there is a shift (lsl, ...).
718c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers              opcode << "mov";
719c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers            }
720c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers            break;
721c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers          case 0x3:
722d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz            if (Rn.r != 0xF) {
723c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers              opcode << "orn";
724c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers            } else {
725c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers              opcode << "mvn";
726c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers            }
727c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers            break;
728c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers          case 0x4:
729d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz            if (Rd.r != 0xF) {
730c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers              opcode << "eor";
731c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers            } else {
7324a999e2424610f7a20ea0b0f25828f9205a83536Brian Carlstrom              if (S != 1U) {
7334a999e2424610f7a20ea0b0f25828f9205a83536Brian Carlstrom                opcode << "UNKNOWN TEQ-" << S;
7344a999e2424610f7a20ea0b0f25828f9205a83536Brian Carlstrom                break;
7354a999e2424610f7a20ea0b0f25828f9205a83536Brian Carlstrom              }
736c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers              opcode << "teq";
737c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers              S = 0;  // don't print 's'
738c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers            }
739c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers            break;
740c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers          case 0x6: opcode << "pkh"; break;
741c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers          case 0x8:
742d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz            if (Rd.r != 0xF) {
743c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers              opcode << "add";
744c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers            } else {
7454a999e2424610f7a20ea0b0f25828f9205a83536Brian Carlstrom              if (S != 1U) {
7464a999e2424610f7a20ea0b0f25828f9205a83536Brian Carlstrom                opcode << "UNKNOWN CMN-" << S;
7474a999e2424610f7a20ea0b0f25828f9205a83536Brian Carlstrom                break;
7484a999e2424610f7a20ea0b0f25828f9205a83536Brian Carlstrom              }
749c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers              opcode << "cmn";
750c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers              S = 0;  // don't print 's'
751c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers            }
752c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers            break;
753c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers          case 0xA: opcode << "adc"; break;
754c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers          case 0xB: opcode << "sbc"; break;
755d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz          case 0xD:
756d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz            if (Rd.r != 0xF) {
757d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz              opcode << "sub";
758d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz            } else {
7594a999e2424610f7a20ea0b0f25828f9205a83536Brian Carlstrom              if (S != 1U) {
7604a999e2424610f7a20ea0b0f25828f9205a83536Brian Carlstrom                opcode << "UNKNOWN CMP-" << S;
7614a999e2424610f7a20ea0b0f25828f9205a83536Brian Carlstrom                break;
7624a999e2424610f7a20ea0b0f25828f9205a83536Brian Carlstrom              }
763d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz              opcode << "cmp";
764d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz              S = 0;  // don't print 's'
765d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz            }
766d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz            break;
767d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz          case 0xE: opcode << "rsb"; break;
768d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz          default: opcode << "UNKNOWN DPSR-" << op3; break;
7693a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        }
770087b2419f432c7d1c32da27c528af4701adb6abdIan Rogers
771c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers        if (S == 1) {
772c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers          opcode << "s";
773c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers        }
774c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers        opcode << ".w";
775d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz
776d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz        if (Rd.r != 0xF) {
777d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz          args << Rd << ", ";
778d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz        }
779d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz        if (Rn.r != 0xF) {
780d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz          args << Rn << ", ";
781d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz        }
782d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz        args << Rm;
783d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz
784d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz        // Shift operand.
785d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz        bool noShift = (imm5 == 0 && shift_type != 0x3);
786d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz        if (!noShift) {
787d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz          args << ", ";
788d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz          switch (shift_type) {
789d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz            case 0x0: args << "lsl"; break;
790d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz            case 0x1: args << "lsr"; break;
791d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz            case 0x2: args << "asr"; break;
792d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz            case 0x3:
793d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz              if (imm5 == 0) {
794d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz                args << "rrx";
795d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz              } else {
796adf1eaaac71b6b440855d48154c17bfdc326904cVladimir Marko                args << "ror #" << imm5;
797d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz              }
798d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz              break;
799d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz          }
800d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz          if (shift_type != 0x3 /* rrx */) {
8017d180cb41d3104af7c85a5b808bb9f57c264c2a6Dmitriy Ivanov            args << StringPrintf(" #%d", (0 != imm5 || 0 == shift_type) ? imm5 : 32);
802d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz          }
803d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz        }
804d9e63c08f0ebc70085652e5b7b18a8abfa032b1eSebastien Hertz
805c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers      } else if ((op2 & 0x40) == 0x40) {  // 1xx xxxx
806c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers        // Co-processor instructions
807c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers        // |111|1|11|000000|0000|1111|1100|000|0  |0000|
808c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers        // |5 3|2|10|987654|3  0|54 2|10 8|7 5|4  |   0|
809c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers        // |---|-|--|------|----|----|----|---|---|----|
810c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers        // |332|2|22|222222|1111|1111|1100|000|0  |0000|
811c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers        // |1 9|8|76|543210|9  6|54 2|10 8|7 5|4  |   0|
812c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers        // |---|-|--|------|----|----|----|---|---|----|
813c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers        // |111| |11| op3  | Rn |    |copr|   |op4|    |
814c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers        uint32_t op3 = (instr >> 20) & 0x3F;
815c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers        uint32_t coproc = (instr >> 8) & 0xF;
816c7fe4e080563a5c1fe7d84781bccecee2ce9392dIan Rogers        uint32_t op4 = (instr >> 4) & 0x1;
8177020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison
818ef6a776af2b4b8607d5f91add0ed0e8497100e31Ian Rogers        if (coproc == 0xA || coproc == 0xB) {   // 101x
819dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko          if (op3 < 0x20 && (op3 & ~5) != 0) {     // 0xxxxx and not 000x0x
820dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko            // Extension register load/store instructions
821dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko            // |1111|110|00000|0000|1111|110|0|00000000|
822dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko            // |5  2|1 9|87654|3  0|5  2|1 9|8|7      0|
823dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko            // |----|---|-----|----|----|---|-|--------|
824dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko            // |3322|222|22222|1111|1111|110|0|00000000|
825dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko            // |1  8|7 5|4   0|9  6|5  2|1 9|8|7      0|
826dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko            // |----|---|-----|----|----|---|-|--------|
827dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko            // |1110|110|PUDWL| Rn | Vd |101|S|  imm8  |
8289af8940be07c83b150c6922fa341b854daf37455Ian Rogers            uint32_t P = (instr >> 24) & 1;
8299af8940be07c83b150c6922fa341b854daf37455Ian Rogers            uint32_t U = (instr >> 23) & 1;
8309af8940be07c83b150c6922fa341b854daf37455Ian Rogers            uint32_t W = (instr >> 21) & 1;
831dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko            if (P == U && W == 1) {
832dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              opcode << "UNDEFINED";
833dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko            } else {
834dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              uint32_t L = (instr >> 20) & 1;
835dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              uint32_t S = (instr >> 8) & 1;
836dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              ArmRegister Rn(instr, 16);
837dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              if (P == 1 && W == 0) {  // VLDR
838dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko                FpRegister d(instr, 12, 22);
839dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko                uint32_t imm8 = instr & 0xFF;
840dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko                opcode << (L == 1 ? "vldr" : "vstr");
841dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko                args << d << ", [" << Rn << ", #" << ((U == 1) ? "" : "-")
842dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko                     << (imm8 << 2) << "]";
843ef6a776af2b4b8607d5f91add0ed0e8497100e31Ian Rogers                if (Rn.r == 15 && U == 1) {
844a6e95b32d499811bbb37602fc7446a5a0d05b9f8Aart Bik                  DumpThumb2Literal(args, instr_ptr, lo_adr, hi_adr, U, imm8 << 2, kT2LitHexLong);
845ef6a776af2b4b8607d5f91add0ed0e8497100e31Ian Rogers                }
846dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              } else if (Rn.r == 13 && W == 1 && U == L) {  // VPUSH/VPOP
847dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko                opcode << (L == 1 ? "vpop" : "vpush");
848dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko                args << FpRegisterRange(instr);
849dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              } else {  // VLDM
850dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko                opcode << (L == 1 ? "vldm" : "vstm");
851dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko                args << Rn << ((W == 1) ? "!" : "") << ", "
852dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko                     << FpRegisterRange(instr);
8537020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison              }
854dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              opcode << (S == 1 ? ".f64" : ".f32");
855dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko            }
856dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko          } else if ((op3 >> 1) == 2) {      // 00010x
857dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko            if ((instr & 0xD0) == 0x10) {
858dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              // 64bit transfers between ARM core and extension registers.
859dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              uint32_t L = (instr >> 20) & 1;
860dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              uint32_t S = (instr >> 8) & 1;
861dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              ArmRegister Rt2(instr, 16);
862dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              ArmRegister Rt(instr, 12);
863dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              FpRegister m(instr, 0, 5);
864dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              opcode << "vmov" << (S ? ".f64" : ".f32");
865dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              if (L == 1) {
866dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko                args << Rt << ", " << Rt2 << ", ";
867dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              }
868dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              if (S) {
869dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko                args << m;
8707020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison              } else {
871dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko                args << m << ", " << FpRegister(m, 1);
872dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              }
873dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              if (L == 0) {
874dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko                args << ", " << Rt << ", " << Rt2;
875dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              }
876dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              if (Rt.r == 15 || Rt.r == 13 || Rt2.r == 15 || Rt2.r == 13 ||
877dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko                  (S == 0 && m.r == 31) || (L == 1 && Rt.r == Rt2.r)) {
878dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko                args << " (UNPREDICTABLE)";
8797020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison              }
8809af8940be07c83b150c6922fa341b854daf37455Ian Rogers            }
8817020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          } else if ((op3 >> 4) == 2 && op4 == 0) {     // 10xxxx, op = 0
8827020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison            // fp data processing
883c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko            // VMLA, VMLS, VMUL, VNMUL, VADD, VSUB, VDIV, VMOV, ...
884c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko            // |1111|1100|0|0|00|0000|1111|110|0|0|0|0|0|0000|
885c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko            // |5  2|1  8|7|6|54|3  0|5  2|1 9|8|7|6|5|4|3  0|
886c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko            // |----|----|-|-|--|----|----|---|-|-|-|-|-|----|
887c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko            // |3322|2222|2|2|22|1111|1111|110|0|0|0|0|0|0000|
888c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko            // |1  8|7  4|3|2|10|9  6|5  2|1 9|8|7|6|5|4|3  0|
889c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko            // |----|----|-|-|--|----|----|---|-|-|-|-|-|----|
890c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko            // |1110|1110|  op3 | Vn | Vd |101|S|N|Q|M|0| Vm |
891c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko            // |1110|1110|0|D|00| Vn | Vd |101|S|N|0|M|0| Vm | VMLA
892c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko            // |1110|1110|0|D|00| Vn | Vd |101|S|N|1|M|0| Vm | VMLS
893c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko            // |1110|1110|0|D|10| Vn | Vd |101|S|N|0|M|0| Vm | VMUL
894c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko            // |1110|1110|0|D|10| Vn | Vd |101|S|N|1|M|0| Vm | VNMUL
895c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko            // |1110|1110|0|D|11| Vn | Vd |101|S|N|0|M|0| Vm | VADD
896c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko            // |1110|1110|0|D|11| Vn | Vd |101|S|N|1|M|0| Vm | VSUB
897c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko            // |1110|1110|1|D|00| Vn | Vd |101|S|N|0|M|0| Vm | VDIV
898c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko            // |1110|1110|1|D|11| iH | Vd |101|S|0|0|0|0| iL | VMOV (imm)
899c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko            // |1110|1110|1|D|11|op5 | Vd |101|S|.|1|M|0| Vm | ... (see below)
900c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko            uint32_t S = (instr >> 8) & 1;
901c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko            uint32_t Q = (instr >> 6) & 1;
902c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko            FpRegister d(instr, 12, 22);
903c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko            FpRegister n(instr, 16, 7);
904c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko            FpRegister m(instr, 0, 5);
905e19649a91702234f9aa9941d76da447a1e0dcc2aZheng Xu            if ((op3 & 0xB) == 0) {  // 100x00
906c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko              opcode << (Q == 0 ? "vmla" : "vmls") << (S != 0 ? ".f64" : ".f32");
907e19649a91702234f9aa9941d76da447a1e0dcc2aZheng Xu              args << d << ", " << n << ", " << m;
908c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko            } else if ((op3 & 0xB) == 0x2) {  // 100x10
909c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko              opcode << (Q == 0 ? "vmul" : "vnmul") << (S != 0 ? ".f64" : ".f32");
910c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko              args << d << ", " << n << ", " << m;
911c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko            } else if ((op3 & 0xB) == 0x3) {  // 100x11
912c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko              opcode << (Q == 0 ? "vadd" : "vsub") << (S != 0 ? ".f64" : ".f32");
913c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko              args << d << ", " << n << ", " << m;
914c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko            } else if ((op3 & 0xB) == 0x8 && Q == 0) {  // 101x00, Q == 0
915c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko              opcode << "vdiv" << (S != 0 ? ".f64" : ".f32");
916c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko              args << d << ", " << n << ", " << m;
917c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko            } else if ((op3 & 0xB) == 0xB && Q == 0) {  // 101x11, Q == 0
918c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko              uint32_t imm8 = ((instr & 0xf0000u) >> 12) | (instr & 0xfu);
919c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko              opcode << "vmov" << (S != 0 ? ".f64" : ".f32");
920c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko              args << d << ", " << (S != 0 ? StringPrintf("0x%016" PRIx64, VFPExpand64(imm8))
921c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                                           : StringPrintf("0x%08x", VFPExpand32(imm8)));
922c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko              if ((instr & 0xa0) != 0) {
923c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                args << " (UNPREDICTABLE)";
924c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko              }
925c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko            } else if ((op3 & 0xB) == 0xB && Q == 1) {  // 101x11, Q == 1
926c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko              // VNEG, VSQRT, VCMP, VCMPE, VCVT (floating-point conversion)
927c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko              // |1111|1100|0|0|00|0000|1111|110|0|0 |0|0|0|0000|
928c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko              // |5  2|1  8|7|6|54|3  0|5  2|1 9|8|7 |6|5|4|3  0|
929c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko              // |----|----|-|-|--|----|----|---|-|- |-|-|-|----|
930c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko              // |3322|2222|2|2|22|1111|1111|110|0|0 |0|0|0|0000|
931c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko              // |1  8|7  4|3|2|10|9  6|5  2|1 9|8|7 |6|5|4|3  0|
932c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko              // |----|----|-|-|--|----|----|---|-|- |-|-|-|----|
933c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko              // |1110|1110|1|D|11|0000| Vd |101|S|0 |1|M|0| Vm | VMOV (reg)
934c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko              // |1110|1110|1|D|11|0000| Vd |101|S|1 |1|M|0| Vm | VABS
935c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko              // |1110|1110|1|D|11|0001| Vd |101|S|0 |1|M|0| Vm | VNEG
936c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko              // |1110|1110|1|D|11|0001| Vd |101|S|1 |1|M|0| Vm | VSQRT
937c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko              // |1110|1110|1|D|11|0100| Vd |101|S|op|1|M|0| Vm | VCMP
938c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko              // |1110|1110|1|D|11|0101| Vd |101|S|op|1|0|0|0000| VCMPE
939c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko              // |1110|1110|1|D|11|op5 | Vd |101|S|op|1|M|0| Vm | VCVT
940c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko              uint32_t op5 = (instr >> 16) & 0xF;
941c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko              uint32_t op = (instr >> 7) & 1;
942c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko              // Register types in VCVT instructions rely on the combination of op5 and S.
943c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko              FpRegister Dd(instr, 12, 22, 1);
944c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko              FpRegister Sd(instr, 12, 22, 0);
945c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko              FpRegister Dm(instr, 0, 5, 1);
946c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko              FpRegister Sm(instr, 0, 5, 0);
947c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko              if (op5 == 0) {
948c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                opcode << (op == 0 ? "vmov" : "vabs") << (S != 0 ? ".f64" : ".f32");
949c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                args << d << ", " << m;
950c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko              } else if (op5 == 1) {
951c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                opcode << (op != 0 ? "vsqrt" : "vneg") << (S != 0 ? ".f64" : ".f32");
952c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                args << d << ", " << m;
953c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko              } else if (op5 == 4) {
954c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                opcode << "vcmp" << (S != 0 ? ".f64" : ".f32");
955c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                args << d << ", " << m;
956c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                if (op != 0) {
957c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                  args << " (quiet nan)";
958c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                }
959c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko              } else if (op5 == 5) {
960c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                opcode << "vcmpe" << (S != 0 ? ".f64" : ".f32");
961c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                args << d << ", #0.0";
962c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                if (op != 0) {
963c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                  args << " (quiet nan)";
964c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                }
965c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                if ((instr & 0x2f) != 0) {
966c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                  args << " (UNPREDICTABLE)";
967c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                }
968c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko              } else if (op5 == 0xD) {
969c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                if (S == 1) {
970c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                  // vcvt{r}.s32.f64
971c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                  opcode << "vcvt" << (op == 0 ? "r" : "") << ".s32.f64";
972c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                  args << Sd << ", " << Dm;
973c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                } else {
974c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                  // vcvt{r}.s32.f32
975c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                  opcode << "vcvt" << (op == 0 ? "r" : "") << ".s32.f32";
976c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                  args << Sd << ", " << Sm;
977c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                }
978c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko              } else if (op5 == 0xC) {
979c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                if (S == 1) {
980c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                  // vcvt{r}.u32.f64
981c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                  opcode << "vcvt" << (op == 0 ? "r" : "") << ".u32.f64";
982c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                  args << Sd << ", " << Dm;
983c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                } else {
984c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                  // vcvt{r}.u32.f32
985c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                  opcode << "vcvt" << (op == 0 ? "r" : "") << ".u32.f32";
986c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                  args << Sd << ", " << Sm;
987c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                }
988c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko              } else if (op5 == 0x8) {
989c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                if (S == 1) {
990c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                  // vcvt.f64.<Tm>
991c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                  opcode << "vcvt.f64." << (op == 0 ? "u" : "s") << "32";
992c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                  args << Dd << ", " << Sm;
993c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                } else {
994c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                  // vcvt.f32.<Tm>
995c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                  opcode << "vcvt.f32." << (op == 0 ? "u" : "s") << "32";
996c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                  args << Sd << ", " << Sm;
997c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                }
998c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko              } else if (op5 == 0x7) {
999c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                if (op == 1) {
1000e19649a91702234f9aa9941d76da447a1e0dcc2aZheng Xu                  if (S == 1) {
1001c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                    // vcvt.f64.f32
1002c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                    opcode << "vcvt.f64.f32";
1003e19649a91702234f9aa9941d76da447a1e0dcc2aZheng Xu                    args << Dd << ", " << Sm;
1004e19649a91702234f9aa9941d76da447a1e0dcc2aZheng Xu                  } else {
1005c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                    // vcvt.f32.f64
1006c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                    opcode << "vcvt.f32.f64";
1007c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                    args << Sd << ", " << Dm;
1008e19649a91702234f9aa9941d76da447a1e0dcc2aZheng Xu                  }
1009e19649a91702234f9aa9941d76da447a1e0dcc2aZheng Xu                }
1010c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko              } else if ((op5 & 0xa) == 0xa) {
1011c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                opcode << "vcvt";
1012c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko                args << "[undecoded: floating <-> fixed]";
1013e19649a91702234f9aa9941d76da447a1e0dcc2aZheng Xu              }
1014e19649a91702234f9aa9941d76da447a1e0dcc2aZheng Xu            }
10157020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          } else if ((op3 >> 4) == 2 && op4 == 1) {     // 10xxxx, op = 1
1016dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko            if (coproc == 10 && (op3 & 0xE) == 0) {
1017dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              // VMOV (between ARM core register and single-precision register)
1018dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              // |1111|1100|000|0 |0000|1111|1100|0|00|0|0000|
1019dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              // |5   |1  8|7 5|4 |3  0|5  2|1  8|7|65|4|3  0|
1020dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              // |----|----|---|- |----|----|----|-|--|-|----|
1021dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              // |3322|2222|222|2 |1111|1111|1100|0|00|0|0000|
1022dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              // |1  8|7  4|3 1|0 |9  6|5  2|1  8|7|65|4|3  0|
1023dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              // |----|----|---|- |----|----|----|-|--|-|----|
1024dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              // |1110|1110|000|op| Vn | Rt |1010|N|00|1|0000|
1025dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              uint32_t op = op3 & 1;
1026dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              ArmRegister Rt(instr, 12);
1027dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              FpRegister n(instr, 16, 7);
1028dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              opcode << "vmov.f32";
1029dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              if (op) {
1030dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko                args << Rt << ", " << n;
1031dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              } else {
1032dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko                args << n << ", " << Rt;
1033dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              }
1034dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              if (Rt.r == 13 || Rt.r == 15 || (instr & 0x6F) != 0) {
1035dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko                args << " (UNPREDICTABLE)";
1036dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              }
1037dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko            } else if (coproc == 10 && op3 == 0x2F) {
1038dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              // VMRS
1039dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              // |1111|11000000|0000|1111|1100|000|0|0000|
1040dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              // |5   |1      4|3  0|5  2|1  8|7 5|4|3  0|
1041dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              // |----|--------|----|----|----|---|-|----|
1042dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              // |3322|22222222|1111|1111|1100|000|0|0000|
1043dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              // |1  8|7      0|9  6|5  2|1  8|7 5|4|3  0|
1044dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              // |----|--------|----|----|----|---|-|----|
1045dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              // |1110|11101111|reg | Rt |1010|000|1|0000| - last 7 0s are (0)
1046dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              uint32_t spec_reg = (instr >> 16) & 0xF;
1047dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              ArmRegister Rt(instr, 12);
1048dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              opcode << "vmrs";
1049dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              if (spec_reg == 1) {
1050dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko                if (Rt.r == 15) {
1051dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko                  args << "APSR_nzcv, FPSCR";
1052dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko                } else if (Rt.r == 13) {
1053dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko                  args << Rt << ", FPSCR (UNPREDICTABLE)";
1054dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko                } else {
1055dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko                  args << Rt << ", FPSCR";
1056dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko                }
1057dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              } else {
1058dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko                args << "(PRIVILEGED)";
1059dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              }
1060dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko            } else if (coproc == 11 && (op3 & 0x9) != 8) {
1061dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko              // VMOV (ARM core register to scalar or vice versa; 8/16/32-bit)
1062dd577a3c9849105429fe7afb3559773d59aaafb6Vladimir Marko            }
10639af8940be07c83b150c6922fa341b854daf37455Ian Rogers          }
10647020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison        }
10653a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      }
10663a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      break;
106740627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers    case 2:
106840627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers      if ((instr & 0x8000) == 0 && (op2 & 0x20) == 0) {
106940627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers        // Data-processing (modified immediate)
107040627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers        // |111|11|10|0000|0|0000|1|111|1100|00000000|
107140627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers        // |5 3|21|09|8765|4|3  0|5|4 2|10 8|7 5    0|
107240627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers        // |---|--|--|----|-|----|-|---|----|--------|
107340627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers        // |332|22|22|2222|2|1111|1|111|1100|00000000|
107440627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers        // |1 9|87|65|4321|0|9  6|5|4 2|10 8|7 5    0|
107540627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers        // |---|--|--|----|-|----|-|---|----|--------|
107640627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers        // |111|10|i0| op3|S| Rn |0|iii| Rd |iiiiiiii|
107740627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers        //  111 10 x0 xxxx x xxxx opxxx xxxx xxxxxxxx
107840627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers        uint32_t i = (instr >> 26) & 1;
107940627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers        uint32_t op3 = (instr >> 21) & 0xF;
108040627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers        uint32_t S = (instr >> 20) & 1;
1081630e77d4648093ce9870c7558d78edea24eab06dElliott Hughes        ArmRegister Rn(instr, 16);
108240627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers        uint32_t imm3 = (instr >> 12) & 7;
1083630e77d4648093ce9870c7558d78edea24eab06dElliott Hughes        ArmRegister Rd(instr, 8);
108440627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers        uint32_t imm8 = instr & 0xFF;
10857cb0f9cf9c7798ae9c4d6cad47e7861f7a511f7eJeff Hao        int32_t imm32 = (i << 11) | (imm3 << 8) | imm8;
10867cb0f9cf9c7798ae9c4d6cad47e7861f7a511f7eJeff Hao        if (Rn.r == 0xF && (op3 == 0x2 || op3 == 0x3)) {
10877cb0f9cf9c7798ae9c4d6cad47e7861f7a511f7eJeff Hao          if (op3 == 0x2) {
10887cb0f9cf9c7798ae9c4d6cad47e7861f7a511f7eJeff Hao            opcode << "mov";
10897cb0f9cf9c7798ae9c4d6cad47e7861f7a511f7eJeff Hao            if (S == 1) {
10907cb0f9cf9c7798ae9c4d6cad47e7861f7a511f7eJeff Hao              opcode << "s";
10917cb0f9cf9c7798ae9c4d6cad47e7861f7a511f7eJeff Hao            }
10927cb0f9cf9c7798ae9c4d6cad47e7861f7a511f7eJeff Hao            opcode << ".w";
10937cb0f9cf9c7798ae9c4d6cad47e7861f7a511f7eJeff Hao          } else {
10947cb0f9cf9c7798ae9c4d6cad47e7861f7a511f7eJeff Hao            opcode << "mvn";
10957cb0f9cf9c7798ae9c4d6cad47e7861f7a511f7eJeff Hao            if (S == 1) {
10967cb0f9cf9c7798ae9c4d6cad47e7861f7a511f7eJeff Hao              opcode << "s";
10977cb0f9cf9c7798ae9c4d6cad47e7861f7a511f7eJeff Hao            }
10987cb0f9cf9c7798ae9c4d6cad47e7861f7a511f7eJeff Hao          }
1099a9650dd5e7195aec987a69a6ebbdaf33f73a6b00Ian Rogers          args << Rd << ", #" << ThumbExpand(imm32);
11007cb0f9cf9c7798ae9c4d6cad47e7861f7a511f7eJeff Hao        } else if (Rd.r == 0xF && S == 1 &&
11017cb0f9cf9c7798ae9c4d6cad47e7861f7a511f7eJeff Hao                   (op3 == 0x0 || op3 == 0x4 || op3 == 0x8 || op3 == 0xD)) {
11027cb0f9cf9c7798ae9c4d6cad47e7861f7a511f7eJeff Hao          if (op3 == 0x0) {
11037cb0f9cf9c7798ae9c4d6cad47e7861f7a511f7eJeff Hao            opcode << "tst";
11047cb0f9cf9c7798ae9c4d6cad47e7861f7a511f7eJeff Hao          } else if (op3 == 0x4) {
11057cb0f9cf9c7798ae9c4d6cad47e7861f7a511f7eJeff Hao            opcode << "teq";
11067cb0f9cf9c7798ae9c4d6cad47e7861f7a511f7eJeff Hao          } else if (op3 == 0x8) {
11072247984899247b1402408d39731ff64048f0e274Vladimir Marko            opcode << "cmn.w";
11087cb0f9cf9c7798ae9c4d6cad47e7861f7a511f7eJeff Hao          } else {
11097cb0f9cf9c7798ae9c4d6cad47e7861f7a511f7eJeff Hao            opcode << "cmp.w";
11107cb0f9cf9c7798ae9c4d6cad47e7861f7a511f7eJeff Hao          }
1111a9650dd5e7195aec987a69a6ebbdaf33f73a6b00Ian Rogers          args << Rn << ", #" << ThumbExpand(imm32);
11127cb0f9cf9c7798ae9c4d6cad47e7861f7a511f7eJeff Hao        } else {
11137cb0f9cf9c7798ae9c4d6cad47e7861f7a511f7eJeff Hao          switch (op3) {
11147cb0f9cf9c7798ae9c4d6cad47e7861f7a511f7eJeff Hao            case 0x0: opcode << "and"; break;
11157cb0f9cf9c7798ae9c4d6cad47e7861f7a511f7eJeff Hao            case 0x1: opcode << "bic"; break;
11167cb0f9cf9c7798ae9c4d6cad47e7861f7a511f7eJeff Hao            case 0x2: opcode << "orr"; break;
11177cb0f9cf9c7798ae9c4d6cad47e7861f7a511f7eJeff Hao            case 0x3: opcode << "orn"; break;
11187cb0f9cf9c7798ae9c4d6cad47e7861f7a511f7eJeff Hao            case 0x4: opcode << "eor"; break;
11197cb0f9cf9c7798ae9c4d6cad47e7861f7a511f7eJeff Hao            case 0x8: opcode << "add"; break;
11207cb0f9cf9c7798ae9c4d6cad47e7861f7a511f7eJeff Hao            case 0xA: opcode << "adc"; break;
11217cb0f9cf9c7798ae9c4d6cad47e7861f7a511f7eJeff Hao            case 0xB: opcode << "sbc"; break;
11227cb0f9cf9c7798ae9c4d6cad47e7861f7a511f7eJeff Hao            case 0xD: opcode << "sub"; break;
11237cb0f9cf9c7798ae9c4d6cad47e7861f7a511f7eJeff Hao            case 0xE: opcode << "rsb"; break;
11247cb0f9cf9c7798ae9c4d6cad47e7861f7a511f7eJeff Hao            default: opcode << "UNKNOWN DPMI-" << op3; break;
11257cb0f9cf9c7798ae9c4d6cad47e7861f7a511f7eJeff Hao          }
11267cb0f9cf9c7798ae9c4d6cad47e7861f7a511f7eJeff Hao          if (S == 1) {
11277cb0f9cf9c7798ae9c4d6cad47e7861f7a511f7eJeff Hao            opcode << "s";
11287cb0f9cf9c7798ae9c4d6cad47e7861f7a511f7eJeff Hao          }
1129a9650dd5e7195aec987a69a6ebbdaf33f73a6b00Ian Rogers          args << Rd << ", " << Rn << ", #" << ThumbExpand(imm32);
113040627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers        }
113140627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers      } else if ((instr & 0x8000) == 0 && (op2 & 0x20) != 0) {
113240627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers        // Data-processing (plain binary immediate)
113340627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers        // |111|11|10|00000|0000|1|111110000000000|
113440627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers        // |5 3|21|09|87654|3  0|5|4   0    5    0|
113540627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers        // |---|--|--|-----|----|-|---------------|
113640627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers        // |332|22|22|22222|1111|1|111110000000000|
113740627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers        // |1 9|87|65|43210|9  6|5|4   0    5    0|
113840627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers        // |---|--|--|-----|----|-|---------------|
113940627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers        // |111|10|x1| op3 | Rn |0|xxxxxxxxxxxxxxx|
114040627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers        uint32_t op3 = (instr >> 20) & 0x1F;
114140627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers        switch (op3) {
1142550191374245cc43089c916a34b292cc4e617dafIan Rogers          case 0x00: case 0x0A: {
1143550191374245cc43089c916a34b292cc4e617dafIan Rogers            // ADD/SUB.W Rd, Rn #imm12 - 111 10 i1 0101 0 nnnn 0 iii dddd iiiiiiii
114466a3fca76997b2d33900faf3ef0cf8226d3a0b58Ian Rogers            ArmRegister Rd(instr, 8);
114566a3fca76997b2d33900faf3ef0cf8226d3a0b58Ian Rogers            ArmRegister Rn(instr, 16);
114666a3fca76997b2d33900faf3ef0cf8226d3a0b58Ian Rogers            uint32_t i = (instr >> 26) & 1;
114766a3fca76997b2d33900faf3ef0cf8226d3a0b58Ian Rogers            uint32_t imm3 = (instr >> 12) & 0x7;
114866a3fca76997b2d33900faf3ef0cf8226d3a0b58Ian Rogers            uint32_t imm8 = instr & 0xFF;
114966a3fca76997b2d33900faf3ef0cf8226d3a0b58Ian Rogers            uint32_t imm12 = (i << 11) | (imm3 << 8) | imm8;
115066a3fca76997b2d33900faf3ef0cf8226d3a0b58Ian Rogers            if (Rn.r != 0xF) {
1151550191374245cc43089c916a34b292cc4e617dafIan Rogers              opcode << (op3 == 0 ? "addw" : "subw");
115266a3fca76997b2d33900faf3ef0cf8226d3a0b58Ian Rogers              args << Rd << ", " << Rn << ", #" << imm12;
115366a3fca76997b2d33900faf3ef0cf8226d3a0b58Ian Rogers            } else {
115466a3fca76997b2d33900faf3ef0cf8226d3a0b58Ian Rogers              opcode << "adr";
115566a3fca76997b2d33900faf3ef0cf8226d3a0b58Ian Rogers              args << Rd << ", ";
1156550191374245cc43089c916a34b292cc4e617dafIan Rogers              DumpBranchTarget(args, instr_ptr + 4, (op3 == 0) ? imm12 : -imm12);
115766a3fca76997b2d33900faf3ef0cf8226d3a0b58Ian Rogers            }
115866a3fca76997b2d33900faf3ef0cf8226d3a0b58Ian Rogers            break;
115966a3fca76997b2d33900faf3ef0cf8226d3a0b58Ian Rogers          }
1160550191374245cc43089c916a34b292cc4e617dafIan Rogers          case 0x04: case 0x0C: {
1161550191374245cc43089c916a34b292cc4e617dafIan Rogers            // MOVW/T Rd, #imm16     - 111 10 i0 0010 0 iiii 0 iii dddd iiiiiiii
1162630e77d4648093ce9870c7558d78edea24eab06dElliott Hughes            ArmRegister Rd(instr, 8);
116340627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers            uint32_t i = (instr >> 26) & 1;
116440627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers            uint32_t imm3 = (instr >> 12) & 0x7;
116540627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers            uint32_t imm8 = instr & 0xFF;
1166630e77d4648093ce9870c7558d78edea24eab06dElliott Hughes            uint32_t Rn = (instr >> 16) & 0xF;
116740627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers            uint32_t imm16 = (Rn << 12) | (i << 11) | (imm3 << 8) | imm8;
1168550191374245cc43089c916a34b292cc4e617dafIan Rogers            opcode << (op3 == 0x04 ? "movw" : "movt");
1169630e77d4648093ce9870c7558d78edea24eab06dElliott Hughes            args << Rd << ", #" << imm16;
117040627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers            break;
117140627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers          }
11728cdbc2aef0ece0f3665966e793c075844b52b67dVladimir Marko          case 0x16: case 0x14: case 0x1C: {
1173eae2691d6120e2f34845eaffec5358d9dd8618ebjeffhao            // BFI Rd, Rn, #lsb, #width - 111 10 0 11 011 0 nnnn 0 iii dddd ii 0 iiiii
11748cdbc2aef0ece0f3665966e793c075844b52b67dVladimir Marko            // SBFX Rd, Rn, #lsb, #width - 111 10 0 11 010 0 nnnn 0 iii dddd ii 0 iiiii
11758cdbc2aef0ece0f3665966e793c075844b52b67dVladimir Marko            // UBFX Rd, Rn, #lsb, #width - 111 10 0 11 110 0 nnnn 0 iii dddd ii 0 iiiii
1176eae2691d6120e2f34845eaffec5358d9dd8618ebjeffhao            ArmRegister Rd(instr, 8);
1177eae2691d6120e2f34845eaffec5358d9dd8618ebjeffhao            ArmRegister Rn(instr, 16);
1178eae2691d6120e2f34845eaffec5358d9dd8618ebjeffhao            uint32_t msb = instr & 0x1F;
1179eae2691d6120e2f34845eaffec5358d9dd8618ebjeffhao            uint32_t imm2 = (instr >> 6) & 0x3;
1180eae2691d6120e2f34845eaffec5358d9dd8618ebjeffhao            uint32_t imm3 = (instr >> 12) & 0x7;
1181eae2691d6120e2f34845eaffec5358d9dd8618ebjeffhao            uint32_t lsb = (imm3 << 2) | imm2;
1182eae2691d6120e2f34845eaffec5358d9dd8618ebjeffhao            uint32_t width = msb - lsb + 1;
11838cdbc2aef0ece0f3665966e793c075844b52b67dVladimir Marko            if (op3 == 0x16) {
11848cdbc2aef0ece0f3665966e793c075844b52b67dVladimir Marko              if (Rn.r != 0xF) {
11858cdbc2aef0ece0f3665966e793c075844b52b67dVladimir Marko                opcode << "bfi";
11868cdbc2aef0ece0f3665966e793c075844b52b67dVladimir Marko                args << Rd << ", " << Rn << ", #" << lsb << ", #" << width;
11878cdbc2aef0ece0f3665966e793c075844b52b67dVladimir Marko              } else {
11888cdbc2aef0ece0f3665966e793c075844b52b67dVladimir Marko                opcode << "bfc";
11898cdbc2aef0ece0f3665966e793c075844b52b67dVladimir Marko                args << Rd << ", #" << lsb << ", #" << width;
11908cdbc2aef0ece0f3665966e793c075844b52b67dVladimir Marko              }
1191eae2691d6120e2f34845eaffec5358d9dd8618ebjeffhao            } else {
11928cdbc2aef0ece0f3665966e793c075844b52b67dVladimir Marko              opcode << ((op3 & 0x8) != 0u ? "ubfx" : "sbfx");
11938cdbc2aef0ece0f3665966e793c075844b52b67dVladimir Marko              args << Rd << ", " << Rn << ", #" << lsb << ", #" << width;
11948cdbc2aef0ece0f3665966e793c075844b52b67dVladimir Marko              if (Rd.r == 13 || Rd.r == 15 || Rn.r == 13 || Rn.r == 15 ||
11958cdbc2aef0ece0f3665966e793c075844b52b67dVladimir Marko                  (instr & 0x04000020) != 0u) {
11968cdbc2aef0ece0f3665966e793c075844b52b67dVladimir Marko                args << " (UNPREDICTABLE)";
11978cdbc2aef0ece0f3665966e793c075844b52b67dVladimir Marko              }
1198eae2691d6120e2f34845eaffec5358d9dd8618ebjeffhao            }
1199eae2691d6120e2f34845eaffec5358d9dd8618ebjeffhao            break;
1200eae2691d6120e2f34845eaffec5358d9dd8618ebjeffhao          }
120140627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers          default:
120240627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers            break;
120340627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers        }
120440627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers      } else {
120540627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers        // Branches and miscellaneous control
120640627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers        // |111|11|1000000|0000|1|111|1100|00000000|
120740627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers        // |5 3|21|0987654|3  0|5|4 2|10 8|7 5    0|
120840627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers        // |---|--|-------|----|-|---|----|--------|
120940627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers        // |332|22|2222222|1111|1|111|1100|00000000|
121040627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers        // |1 9|87|6543210|9  6|5|4 2|10 8|7 5    0|
121140627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers        // |---|--|-------|----|-|---|----|--------|
121240627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers        // |111|10| op2   |    |1|op3|op4 |        |
121340627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers
121440627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers        uint32_t op3 = (instr >> 12) & 7;
12157934ac288acfb2552bb0b06ec1f61e5820d924a4Brian Carlstrom        // uint32_t op4 = (instr >> 8) & 0xF;
121640627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers        switch (op3) {
121740627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers          case 0:
121840627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers            if ((op2 & 0x38) != 0x38) {
121940627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers              // Conditional branch
122040627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers              // |111|11|1|0000|000000|1|1|1 |1|1 |10000000000|
122140627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers              // |5 3|21|0|9876|543  0|5|4|3 |2|1 |0    5    0|
122240627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers              // |---|--|-|----|------|-|-|--|-|--|-----------|
122340627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers              // |332|22|2|2222|221111|1|1|1 |1|1 |10000000000|
122440627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers              // |1 9|87|6|5432|109  6|5|4|3 |2|1 |0    5    0|
122540627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers              // |---|--|-|----|------|-|-|--|-|--|-----------|
122640627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers              // |111|10|S|cond| imm6 |1|0|J1|0|J2| imm11     |
122740627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers              uint32_t S = (instr >> 26) & 1;
122840627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers              uint32_t J2 = (instr >> 11) & 1;
122940627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers              uint32_t J1 = (instr >> 13) & 1;
123040627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers              uint32_t imm6 = (instr >> 16) & 0x3F;
123140627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers              uint32_t imm11 = instr & 0x7FF;
123240627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers              uint32_t cond = (instr >> 22) & 0xF;
123340627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers              int32_t imm32 = (S << 20) |  (J2 << 19) | (J1 << 18) | (imm6 << 12) | (imm11 << 1);
123440627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers              imm32 = (imm32 << 11) >> 11;  // sign extend 21bit immediate
1235cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes              opcode << "b";
1236cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes              DumpCond(opcode, cond);
1237cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes              opcode << ".w";
1238cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes              DumpBranchTarget(args, instr_ptr + 4, imm32);
12399af8940be07c83b150c6922fa341b854daf37455Ian Rogers            } else if (op2 == 0x3B) {
12409af8940be07c83b150c6922fa341b854daf37455Ian Rogers              // Miscellaneous control instructions
12419af8940be07c83b150c6922fa341b854daf37455Ian Rogers              uint32_t op5 = (instr >> 4) & 0xF;
12429af8940be07c83b150c6922fa341b854daf37455Ian Rogers              switch (op5) {
1243b122a4bbed34ab22b4c1541ee25e5cf22f12a926Ian Rogers                case 4: opcode << "dsb"; DumpMemoryDomain(args, instr & 0xF); break;
1244b122a4bbed34ab22b4c1541ee25e5cf22f12a926Ian Rogers                case 5: opcode << "dmb"; DumpMemoryDomain(args, instr & 0xF); break;
1245b122a4bbed34ab22b4c1541ee25e5cf22f12a926Ian Rogers                case 6: opcode << "isb"; DumpMemoryDomain(args, instr & 0xF); break;
12469af8940be07c83b150c6922fa341b854daf37455Ian Rogers              }
124740627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers            }
124840627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers            break;
124940627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers          case 2:
1250d0876a9b6d1b58409f642c3886cabb42bcd0ae09Ian Rogers            if ((op2 & 0x38) == 0x38) {
1251d0876a9b6d1b58409f642c3886cabb42bcd0ae09Ian Rogers              if (op2 == 0x7F) {
1252d0876a9b6d1b58409f642c3886cabb42bcd0ae09Ian Rogers                opcode << "udf";
1253d0876a9b6d1b58409f642c3886cabb42bcd0ae09Ian Rogers              }
1254d0876a9b6d1b58409f642c3886cabb42bcd0ae09Ian Rogers              break;
1255d0876a9b6d1b58409f642c3886cabb42bcd0ae09Ian Rogers            }
1256fc787ecd91127b2c8458afd94e5148e2ae51a1f5Ian Rogers            FALLTHROUGH_INTENDED;  // Else deliberate fall-through to B.
1257d0876a9b6d1b58409f642c3886cabb42bcd0ae09Ian Rogers          case 1: case 3: {
1258d0876a9b6d1b58409f642c3886cabb42bcd0ae09Ian Rogers            // B
1259d0876a9b6d1b58409f642c3886cabb42bcd0ae09Ian Rogers            // |111|11|1|0000|000000|11|1 |1|1 |10000000000|
1260d0876a9b6d1b58409f642c3886cabb42bcd0ae09Ian Rogers            // |5 3|21|0|9876|543  0|54|3 |2|1 |0    5    0|
1261d0876a9b6d1b58409f642c3886cabb42bcd0ae09Ian Rogers            // |---|--|-|----|------|--|--|-|--|-----------|
1262d0876a9b6d1b58409f642c3886cabb42bcd0ae09Ian Rogers            // |332|22|2|2222|221111|11|1 |1|1 |10000000000|
1263d0876a9b6d1b58409f642c3886cabb42bcd0ae09Ian Rogers            // |1 9|87|6|5  2|10   6|54|3 |2|1 |0    5    0|
1264d0876a9b6d1b58409f642c3886cabb42bcd0ae09Ian Rogers            // |---|--|-|----|------|--|--|-|--|-----------|
1265d0876a9b6d1b58409f642c3886cabb42bcd0ae09Ian Rogers            // |111|10|S|cond| imm6 |10|J1|0|J2| imm11     |
1266d0876a9b6d1b58409f642c3886cabb42bcd0ae09Ian Rogers            // |111|10|S| imm10     |10|J1|1|J2| imm11     |
1267d0876a9b6d1b58409f642c3886cabb42bcd0ae09Ian Rogers            uint32_t S = (instr >> 26) & 1;
1268d0876a9b6d1b58409f642c3886cabb42bcd0ae09Ian Rogers            uint32_t cond = (instr >> 22) & 0xF;
1269d0876a9b6d1b58409f642c3886cabb42bcd0ae09Ian Rogers            uint32_t J2 = (instr >> 11) & 1;
1270d0876a9b6d1b58409f642c3886cabb42bcd0ae09Ian Rogers            uint32_t form = (instr >> 12) & 1;
1271d0876a9b6d1b58409f642c3886cabb42bcd0ae09Ian Rogers            uint32_t J1 = (instr >> 13) & 1;
1272d0876a9b6d1b58409f642c3886cabb42bcd0ae09Ian Rogers            uint32_t imm10 = (instr >> 16) & 0x3FF;
1273d0876a9b6d1b58409f642c3886cabb42bcd0ae09Ian Rogers            uint32_t imm6  = (instr >> 16) & 0x3F;
1274d0876a9b6d1b58409f642c3886cabb42bcd0ae09Ian Rogers            uint32_t imm11 = instr & 0x7FF;
1275d0876a9b6d1b58409f642c3886cabb42bcd0ae09Ian Rogers            opcode << "b";
1276d0876a9b6d1b58409f642c3886cabb42bcd0ae09Ian Rogers            int32_t imm32;
1277d0876a9b6d1b58409f642c3886cabb42bcd0ae09Ian Rogers            if (form == 0) {
1278d0876a9b6d1b58409f642c3886cabb42bcd0ae09Ian Rogers              DumpCond(opcode, cond);
1279d0876a9b6d1b58409f642c3886cabb42bcd0ae09Ian Rogers              imm32 = (S << 20) | (J2 << 19) | (J1 << 18) | (imm6 << 12) | (imm11 << 1);
1280d0876a9b6d1b58409f642c3886cabb42bcd0ae09Ian Rogers              imm32 = (imm32 << 11) >> 11;  // sign extend 21 bit immediate.
1281d0876a9b6d1b58409f642c3886cabb42bcd0ae09Ian Rogers            } else {
1282369da2211be326ed8d2588866c2928319ba3a807Vladimir Marko              uint32_t I1 = (J1 ^ S) ^ 1;
1283369da2211be326ed8d2588866c2928319ba3a807Vladimir Marko              uint32_t I2 = (J2 ^ S) ^ 1;
1284d0876a9b6d1b58409f642c3886cabb42bcd0ae09Ian Rogers              imm32 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1);
1285369da2211be326ed8d2588866c2928319ba3a807Vladimir Marko              imm32 = (imm32 << 7) >> 7;  // sign extend 25 bit immediate.
1286d0876a9b6d1b58409f642c3886cabb42bcd0ae09Ian Rogers            }
1287d0876a9b6d1b58409f642c3886cabb42bcd0ae09Ian Rogers            opcode << ".w";
1288d0876a9b6d1b58409f642c3886cabb42bcd0ae09Ian Rogers            DumpBranchTarget(args, instr_ptr + 4, imm32);
128940627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers            break;
1290d0876a9b6d1b58409f642c3886cabb42bcd0ae09Ian Rogers          }
129140627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers          case 4: case 6: case 5: case 7: {
129240627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers            // BL, BLX (immediate)
129340627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers            // |111|11|1|0000000000|11|1 |1|1 |10000000000|
129440627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers            // |5 3|21|0|9876543  0|54|3 |2|1 |0    5    0|
129540627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers            // |---|--|-|----------|--|--|-|--|-----------|
129640627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers            // |332|22|2|2222221111|11|1 |1|1 |10000000000|
129740627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers            // |1 9|87|6|5    0   6|54|3 |2|1 |0    5    0|
129840627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers            // |---|--|-|----------|--|--|-|--|-----------|
1299d6ed642458c8820e1beca72f3d7b5f0be4a4b64bDave Allison            // |111|10|S| imm10    |11|J1|L|J2| imm11     |
130040627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers            uint32_t S = (instr >> 26) & 1;
130140627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers            uint32_t J2 = (instr >> 11) & 1;
1302d6ed642458c8820e1beca72f3d7b5f0be4a4b64bDave Allison            uint32_t L = (instr >> 12) & 1;
130340627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers            uint32_t J1 = (instr >> 13) & 1;
130440627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers            uint32_t imm10 = (instr >> 16) & 0x3FF;
130540627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers            uint32_t imm11 = instr & 0x7FF;
1306d6ed642458c8820e1beca72f3d7b5f0be4a4b64bDave Allison            if (L == 0) {
1307d6ed642458c8820e1beca72f3d7b5f0be4a4b64bDave Allison              opcode << "bx";
1308f9487c039efb4112616d438593a2ab02792e0304Dave Allison            } else {
1309d6ed642458c8820e1beca72f3d7b5f0be4a4b64bDave Allison              opcode << "blx";
131040627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers            }
131140627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers            uint32_t I1 = ~(J1 ^ S);
131240627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers            uint32_t I2 = ~(J2 ^ S);
131340627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers            int32_t imm32 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1);
131440627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers            imm32 = (imm32 << 8) >> 8;  // sign extend 24 bit immediate.
1315cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes            DumpBranchTarget(args, instr_ptr + 4, imm32);
131640627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers            break;
131740627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers          }
131840627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers        }
131940627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers      }
132040627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers      break;
13213a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    case 3:
13223a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      switch (op2) {
132355d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko        case 0x07: case 0x0F: case 0x17: case 0x1F: {  // Explicitly UNDEFINED, A6.3.
132455d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          opcode << "UNDEFINED";
132555d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          break;
132655d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko        }
132755d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko        case 0x06: case 0x0E: {  // "Store single data item" undefined opcodes, A6.3.10.
132855d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          opcode << "UNDEFINED [store]";
132955d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          break;
133055d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko        }
133155d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko        case 0x15: case 0x1D: {  // "Load word" undefined opcodes, A6.3.7.
133255d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          opcode << "UNDEFINED [load]";
13333a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          break;
13343a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        }
133555d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko        case 0x10: case 0x12: case 0x14: case 0x16: case 0x18: case 0x1A: case 0x1C: case 0x1E: {
133655d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          opcode << "UNKNOWN " << op2 << " [SIMD]";
133755d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          break;
133855d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko        }
133955d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko        case 0x01: case 0x00: case 0x09: case 0x08:   // {LD,ST}RB{,T}
134055d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko        case 0x03: case 0x02: case 0x0B: case 0x0A:   // {LD,ST}RH{,T}
134155d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko        case 0x05: case 0x04: case 0x0D: case 0x0C:   // {LD,ST}R{,T}
134255d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko        case 0x11:            case 0x19:              // LDRSB{,T} (no signed store)
134355d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko        case 0x13:            case 0x1B: {            // LDRSH{,T} (no signed store)
134455d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          // Load:
134555d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          // (Store is the same except that l==0 and always s==0 below.)
134655d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          //                       00s.whl (sign, word, half, load)
134755d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          // LDR{S}B  imm12: 11111|00s1001| Rn | Rt |imm12             (0x09)
134855d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          // LDR{S}B   imm8: 11111|00s0001| Rn | Rt |1PUW|imm8         (0x01)
134955d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          // LDR{S}BT  imm8: 11111|00s0001| Rn | Rt |1110|imm8         (0x01)
135055d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          // LDR{S}B    lit: 11111|00sU001|1111| Rt |imm12             (0x01/0x09)
135155d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          // LDR{S}B    reg: 11111|00s0001| Rn | Rt |000000|imm2| Rm   (0x01)
135255d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          // LDR{S}H  imm12: 11111|00s1011| Rn | Rt |imm12             (0x0B)
135355d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          // LDR{S}H   imm8: 11111|00s0011| Rn | Rt |1PUW|imm8         (0x03)
135455d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          // LDR{S}HT  imm8: 11111|00s0011| Rn | Rt |1110|imm8         (0x03)
135555d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          // LDR{S}H    lit: 11111|00sU011|1111| Rt |imm12             (0x03/0x0B)
135655d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          // LDR{S}H    reg: 11111|00s0011| Rn | Rt |000000|imm2| Rm   (0x03)
135755d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          // LDR      imm12: 11111|0001101| Rn | Rt |imm12             (0x0D)
135855d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          // LDR       imm8: 11111|0000101| Rn | Rt |1PUW|imm8         (0x05)
135955d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          // LDRT      imm8: 11111|0000101| Rn | Rt |1110|imm8         (0x05)
136055d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          // LDR        lit: 11111|000U101|1111| Rt |imm12             (0x05/0x0D)
136155d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          // LDR        reg: 11111|0000101| Rn | Rt |000000|imm2| Rm   (0x05)
136255d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          //
136355d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          // If Rt == 15, instead of load we have preload:
136455d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          // PLD{W}   imm12: 11111|00010W1| Rn |1111|imm12             (0x09/0x0B)
136555d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          // PLD{W}    imm8: 11111|00000W1| Rn |1111|1100|imm8         (0x01/0x03); -imm8
136655d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          // PLD        lit: 11111|000U001|1111|1111|imm12             (0x01/0x09)
136755d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          // PLD{W}     reg: 11111|00000W1| Rn |1111|000000|imm2| Rm   (0x01/0x03)
136855d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          // PLI      imm12: 11111|0011001| Rn |1111|imm12             (0x19)
136955d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          // PLI       imm8: 11111|0010001| Rn |1111|1100|imm8         (0x11); -imm8
137055d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          // PLI        lit: 11111|001U001|1111|1111|imm12             (0x01/0x09)
137155d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          // PLI        reg: 11111|0010001| Rn |1111|000000|imm2| Rm   (0x01/0x03)
137255d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko
137355d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          bool is_load = HasBitSet(instr, 20);
137455d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          bool is_half = HasBitSet(instr, 21);  // W for PLD/PLDW.
137555d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          bool is_word = HasBitSet(instr, 22);
137655d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          bool is_signed = HasBitSet(instr, 24);
1377eae2691d6120e2f34845eaffec5358d9dd8618ebjeffhao          ArmRegister Rn(instr, 16);
1378eae2691d6120e2f34845eaffec5358d9dd8618ebjeffhao          ArmRegister Rt(instr, 12);
137955d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          uint32_t imm12 = instr & 0xFFF;
138055d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          uint32_t U = (instr >> 23) & 1;  // U for imm12
138155d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          uint32_t imm8 = instr & 0xFF;
138255d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          uint32_t op4 = (instr >> 8) & 0xF;  // 1PUW for imm8
138355d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          if (Rt.r == PC && is_load && !is_word) {
138455d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko            // PLD, PLDW, PLI
138555d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko            const char* pld_pli = (is_signed ? "pli" : "pld");
138655d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko            const char* w = (is_half ? "w" : "");
138755d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko            if (is_signed && !is_half) {
138855d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko              opcode << "UNDEFINED [PLI+W]";
138955d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko            } else if (Rn.r == PC || U != 0u) {
139055d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko              opcode << pld_pli << w;
139155d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko              args << "[" << Rn << ", #" << (U != 0u ? "" : "-") << imm12 << "]";
139255d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko              if (Rn.r == PC && is_half) {
139355d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko                args << " (UNPREDICTABLE)";
1394eae2691d6120e2f34845eaffec5358d9dd8618ebjeffhao              }
139555d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko            } else if ((instr & 0xFC0) == 0) {
139655d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko              opcode << pld_pli << w;
139755d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko              RmLslImm2 Rm(instr);
139855d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko              args << "[" << Rn << ", " << Rm << "]";
139955d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko            } else if (op4 == 0xC) {
140055d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko              opcode << pld_pli << w;
140155d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko              args << "[" << Rn << ", #-" << imm8 << "]";
140255d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko            } else {
140355d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko              opcode << "UNDEFINED [~" << pld_pli << "]";
1404eae2691d6120e2f34845eaffec5358d9dd8618ebjeffhao            }
140555d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko            break;
140655d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          }
140755d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          const char* ldr_str = is_load ? "ldr" : "str";
140855d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          const char* sign = is_signed ? "s" : "";
140955d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          const char* type = is_word ? "" : is_half ? "h" : "b";
141055d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          bool unpred = (Rt.r == SP && !is_word) || (Rt.r == PC && !is_load);
141155d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          if (Rn.r == PC && !is_load) {
141255d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko            opcode << "UNDEFINED [STR-lit]";
141355d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko            unpred = false;
141455d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          } else if (Rn.r == PC || U != 0u) {
141555d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko            // Load/store with imm12 (load literal if Rn.r == PC; there's no store literal).
141655d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko            opcode << ldr_str << sign << type << ".w";
141755d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko            args << Rt << ", [" << Rn << ", #" << (U != 0u ? "" : "-") << imm12 << "]";
141855d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko            if (Rn.r == TR && is_load) {
141955d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko              args << "  ; ";
142055d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko              Thread::DumpThreadOffset<4>(args, imm12);
142155d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko            } else if (Rn.r == PC) {
142255d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko              T2LitType lit_type[] = {
142355d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko                  kT2LitUByte, kT2LitUHalf, kT2LitHexWord, kT2LitInvalid,
142455d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko                  kT2LitUByte, kT2LitUHalf, kT2LitHexWord, kT2LitInvalid,
142555d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko                  kT2LitSByte, kT2LitSHalf, kT2LitInvalid, kT2LitInvalid,
142655d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko                  kT2LitSByte, kT2LitSHalf, kT2LitInvalid, kT2LitInvalid,
142755d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko              };
142855d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko              DCHECK_LT(op2 >> 1, arraysize(lit_type));
142955d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko              DCHECK_NE(lit_type[op2 >> 1], kT2LitInvalid);
1430a6e95b32d499811bbb37602fc7446a5a0d05b9f8Aart Bik              DumpThumb2Literal(args, instr_ptr, lo_adr, hi_adr, U, imm12, lit_type[op2 >> 1]);
143155d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko            }
143255d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          } else if ((instr & 0xFC0) == 0) {
143355d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko            opcode << ldr_str << sign << type << ".w";
143455d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko            RmLslImm2 Rm(instr);
143555d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko            args << Rt << ", [" << Rn << ", " << Rm << "]";
143655d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko            unpred = unpred || (Rm.rm.r == SP) || (Rm.rm.r == PC);
143755d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          } else if (is_word && Rn.r == SP && imm8 == 4 && op4 == (is_load ? 0xB : 0xD)) {
143855d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko            opcode << (is_load ? "pop" : "push") << ".w";
143955d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko            args << Rn;
144055d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko            unpred = unpred || (Rn.r == SP);
144155d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          } else if ((op4 & 5) == 0) {
144255d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko            opcode << "UNDEFINED [P = W = 0 for " << ldr_str << "]";
144355d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko            unpred = false;
144455d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          } else {
144555d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko            uint32_t P = (instr >> 10) & 1;
144655d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko            U = (instr >> 9) & 1;
144755d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko            uint32_t W = (instr >> 8) & 1;
144855d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko            bool pre_index = (P != 0 && W == 1);
144955d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko            bool post_index = (P == 0 && W == 1);
145055d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko            const char* t = (P != 0 && U != 0 && W == 0) ? "t" : "";  // Unprivileged load/store?
145155d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko            opcode << ldr_str << sign << type << t << ".w";
145255d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko            args << Rt << ", [" << Rn << (post_index ? "]" : "") << ", #" << (U != 0 ? "" : "-")
145355d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko                << imm8 << (post_index ? "" : "]") << (pre_index ? "!" : "");
145455d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko            unpred = (W != 0 && Rn.r == Rt.r);
145555d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          }
145655d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          if (unpred) {
145755d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko            args << " (UNPREDICTABLE)";
1458eae2691d6120e2f34845eaffec5358d9dd8618ebjeffhao          }
1459eae2691d6120e2f34845eaffec5358d9dd8618ebjeffhao          break;
1460eae2691d6120e2f34845eaffec5358d9dd8618ebjeffhao        }
1461a8b4caf7526b6b66a8ae0826bd52c39c66e3c714Vladimir Marko        case 0x29: {  // 0101001
1462a8b4caf7526b6b66a8ae0826bd52c39c66e3c714Vladimir Marko          // |111|11|1000000|0000|1111|1100|00|0 0|0000|
1463a8b4caf7526b6b66a8ae0826bd52c39c66e3c714Vladimir Marko          // |5 3|21|0     4|3  0|5  2|1  8|76|5 4|3  0|
1464a8b4caf7526b6b66a8ae0826bd52c39c66e3c714Vladimir Marko          // |---|--|-------|----|----|----|--|---|----|
1465a8b4caf7526b6b66a8ae0826bd52c39c66e3c714Vladimir Marko          // |332|22|2222222|1111|1111|1100|00|0 0|0000|
1466a8b4caf7526b6b66a8ae0826bd52c39c66e3c714Vladimir Marko          // |1 9|87|6     0|9  6|5  2|1  8|76|5 4|3  0|
1467a8b4caf7526b6b66a8ae0826bd52c39c66e3c714Vladimir Marko          // |---|--|-------|----|----|----|--|---|----|
1468a8b4caf7526b6b66a8ae0826bd52c39c66e3c714Vladimir Marko          // |111|11|0101001| Rm |1111| Rd |11|op3| Rm |
1469a8b4caf7526b6b66a8ae0826bd52c39c66e3c714Vladimir Marko          // REV   - 111 11 0101001 mmmm 1111 dddd 1000 mmmm
1470a8b4caf7526b6b66a8ae0826bd52c39c66e3c714Vladimir Marko          // REV16 - 111 11 0101001 mmmm 1111 dddd 1001 mmmm
1471a8b4caf7526b6b66a8ae0826bd52c39c66e3c714Vladimir Marko          // RBIT  - 111 11 0101001 mmmm 1111 dddd 1010 mmmm
1472a8b4caf7526b6b66a8ae0826bd52c39c66e3c714Vladimir Marko          // REVSH - 111 11 0101001 mmmm 1111 dddd 1011 mmmm
1473a8b4caf7526b6b66a8ae0826bd52c39c66e3c714Vladimir Marko          if ((instr & 0xf0c0) == 0xf080) {
1474a8b4caf7526b6b66a8ae0826bd52c39c66e3c714Vladimir Marko            uint32_t op3 = (instr >> 4) & 3;
1475a8b4caf7526b6b66a8ae0826bd52c39c66e3c714Vladimir Marko            opcode << kThumbReverseOperations[op3];
1476a8b4caf7526b6b66a8ae0826bd52c39c66e3c714Vladimir Marko            ArmRegister Rm(instr, 0);
1477a8b4caf7526b6b66a8ae0826bd52c39c66e3c714Vladimir Marko            ArmRegister Rd(instr, 8);
1478a8b4caf7526b6b66a8ae0826bd52c39c66e3c714Vladimir Marko            args << Rd << ", " << Rm;
1479a8b4caf7526b6b66a8ae0826bd52c39c66e3c714Vladimir Marko            ArmRegister Rm2(instr, 16);
1480a8b4caf7526b6b66a8ae0826bd52c39c66e3c714Vladimir Marko            if (Rm.r != Rm2.r || Rm.r == 13 || Rm.r == 15 || Rd.r == 13 || Rd.r == 15) {
1481a8b4caf7526b6b66a8ae0826bd52c39c66e3c714Vladimir Marko              args << " (UNPREDICTABLE)";
1482a8b4caf7526b6b66a8ae0826bd52c39c66e3c714Vladimir Marko            }
14831f6754dc482f0175acb05275a82b9950c3d268eeVladimir Marko          }  // else unknown instruction
1484a8b4caf7526b6b66a8ae0826bd52c39c66e3c714Vladimir Marko          break;
1485a8b4caf7526b6b66a8ae0826bd52c39c66e3c714Vladimir Marko        }
1486611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling        case 0x2B: {  // 0101011
1487611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling          //  CLZ - 111 11 0101011 mmmm 1111 dddd 1000 mmmm
1488611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling          if ((instr & 0xf0f0) == 0xf080) {
1489611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling            opcode << "clz";
1490611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling            ArmRegister Rm(instr, 0);
1491611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling            ArmRegister Rd(instr, 8);
1492611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling            args << Rd << ", " << Rm;
1493611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling            ArmRegister Rm2(instr, 16);
1494611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling            if (Rm.r != Rm2.r || Rm.r == 13 || Rm.r == 15 || Rd.r == 13 || Rd.r == 15) {
1495611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling              args << " (UNPREDICTABLE)";
1496611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling            }
1497611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling          }
1498611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling          break;
1499611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling        }
15007020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison      default:      // more formats
15017020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison        if ((op2 >> 4) == 2) {      // 010xxxx
15027020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          // data processing (register)
1503c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko          if ((instr & 0x0080f0f0) == 0x0000f000) {
1504c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko            // LSL, LSR, ASR, ROR
1505c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko            uint32_t shift_op = (instr >> 21) & 3;
1506c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko            uint32_t S = (instr >> 20) & 1;
1507c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko            ArmRegister Rd(instr, 8);
1508c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko            ArmRegister Rn(instr, 16);
1509c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko            ArmRegister Rm(instr, 0);
1510c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko            opcode << kThumb2ShiftOperations[shift_op] << (S != 0 ? "s" : "");
1511c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko            args << Rd << ", " << Rn << ", " << Rm;
1512c777e0de83cdffdb2e240d439c5595a4836553e8Vladimir Marko          }
15137020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison        } else if ((op2 >> 3) == 6) {       // 0110xxx
15147020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          // Multiply, multiply accumulate, and absolute difference
15157020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          op1 = (instr >> 20) & 0x7;
1516a262f7707330dccfb50af6345813083182b61043Ningsheng Jian          op2 = (instr >> 4) & 0x1;
15177020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          ArmRegister Ra(instr, 12);
15187020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          ArmRegister Rn(instr, 16);
15197020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          ArmRegister Rm(instr, 0);
15207020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          ArmRegister Rd(instr, 8);
15217020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          switch (op1) {
15227020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          case 0:
15237020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison            if (op2 == 0) {
15247020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison              if (Ra.r == 0xf) {
15257020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison                opcode << "mul";
15267020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison                args << Rd << ", " << Rn << ", " << Rm;
15277020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison              } else {
15287020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison                opcode << "mla";
15297020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison                args << Rd << ", " << Rn << ", " << Rm << ", " << Ra;
15307020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison              }
15317020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison            } else {
15327020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison              opcode << "mls";
15337020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison              args << Rd << ", " << Rn << ", " << Rm << ", " << Ra;
15347020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison            }
15357020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison            break;
15367020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          case 1:
15377020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          case 2:
15387020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          case 3:
15397020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          case 4:
15407020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          case 5:
15417020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          case 6:
15427020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison              break;        // do these sometime
15437020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          }
15447020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison        } else if ((op2 >> 3) == 7) {       // 0111xxx
15457020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          // Long multiply, long multiply accumulate, and divide
15467020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          op1 = (instr >> 20) & 0x7;
15477020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          op2 = (instr >> 4) & 0xf;
15487020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          ArmRegister Rn(instr, 16);
15497020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          ArmRegister Rm(instr, 0);
15507020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          ArmRegister Rd(instr, 8);
15517020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          ArmRegister RdHi(instr, 8);
15527020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          ArmRegister RdLo(instr, 12);
15537020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          switch (op1) {
15547020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          case 0:
15557020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison            opcode << "smull";
15567020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison            args << RdLo << ", " << RdHi << ", " << Rn << ", " << Rm;
15577020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison            break;
15587020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          case 1:
15597020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison            opcode << "sdiv";
15607020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison            args << Rd << ", " << Rn << ", " << Rm;
15617020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison            break;
15627020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          case 2:
15637020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison            opcode << "umull";
15647020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison            args << RdLo << ", " << RdHi << ", " << Rn << ", " << Rm;
15657020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison            break;
15667020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          case 3:
15677020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison            opcode << "udiv";
15687020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison            args << Rd << ", " << Rn << ", " << Rm;
15697020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison            break;
15707020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          case 4:
15717020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          case 5:
15727020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          case 6:
15737020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison            break;      // TODO: when we generate these...
15747020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison          }
15757020278bce98a0735dc6abcbd33bdf1ed2634f1dDave Allison        }
15763a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      }
1577fc787ecd91127b2c8458afd94e5148e2ae51a1f5Ian Rogers      break;
15783a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    default:
15793a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      break;
15803a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  }
15819af8940be07c83b150c6922fa341b854daf37455Ian Rogers
15829af8940be07c83b150c6922fa341b854daf37455Ian Rogers  // Apply any IT-block conditions to the opcode if necessary.
15839af8940be07c83b150c6922fa341b854daf37455Ian Rogers  if (!it_conditions_.empty()) {
15849af8940be07c83b150c6922fa341b854daf37455Ian Rogers    opcode << it_conditions_.back();
15859af8940be07c83b150c6922fa341b854daf37455Ian Rogers    it_conditions_.pop_back();
15869af8940be07c83b150c6922fa341b854daf37455Ian Rogers  }
15873c7bb98698f77af10372cf31824d3bb115d9bf0fNicolas Geoffray  if (opcode.str().size() == 0) {
15883c7bb98698f77af10372cf31824d3bb115d9bf0fNicolas Geoffray    opcode << "UNKNOWN " << op2;
15893c7bb98698f77af10372cf31824d3bb115d9bf0fNicolas Geoffray  }
15909af8940be07c83b150c6922fa341b854daf37455Ian Rogers
15912cbaccb67e22c0b313a9785bfc65bcb4b25d0676Brian Carlstrom  os << FormatInstructionPointer(instr_ptr)
15922cbaccb67e22c0b313a9785bfc65bcb4b25d0676Brian Carlstrom     << StringPrintf(": %08x\t%-7s ", instr, opcode.str().c_str())
15932cbaccb67e22c0b313a9785bfc65bcb4b25d0676Brian Carlstrom     << args.str() << '\n';
15943a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  return 4;
15951895ea386ca78573302483f589ebabd8ce1480e7Brian Carlstrom}  // NOLINT(readability/fn_size)
15963a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
15973a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogerssize_t DisassemblerArm::DumpThumb16(std::ostream& os, const uint8_t* instr_ptr) {
15983a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  uint16_t instr = ReadU16(instr_ptr);
15993a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  bool is_32bit = ((instr & 0xF000) == 0xF000) || ((instr & 0xF800) == 0xE800);
16003a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  if (is_32bit) {
16013a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    return DumpThumb32(os, instr_ptr);
16023a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  } else {
1603cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes    std::ostringstream opcode;
1604cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes    std::ostringstream args;
16053a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    uint16_t opcode1 = instr >> 10;
16063a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    if (opcode1 < 0x10) {
16073a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      // shift (immediate), add, subtract, move, and compare
16083a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      uint16_t opcode2 = instr >> 9;
16093a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      switch (opcode2) {
16103a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        case 0x0: case 0x1: case 0x2: case 0x3: case 0x4: case 0x5: case 0x6: case 0x7:
16113a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        case 0x8: case 0x9: case 0xA: case 0xB: {
1612e78500c23c004c9b4756c4a6c4f4069d34e1aa4aSebastien Hertz          // Logical shift left     - 00 000xx iii mmm ddd
1613e78500c23c004c9b4756c4a6c4f4069d34e1aa4aSebastien Hertz          // Logical shift right    - 00 001xx iii mmm ddd
1614e78500c23c004c9b4756c4a6c4f4069d34e1aa4aSebastien Hertz          // Arithmetic shift right - 00 010xx iii mmm ddd
16153a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          uint16_t imm5 = (instr >> 6) & 0x1F;
1616630e77d4648093ce9870c7558d78edea24eab06dElliott Hughes          ThumbRegister rm(instr, 3);
1617e78500c23c004c9b4756c4a6c4f4069d34e1aa4aSebastien Hertz          ThumbRegister Rd(instr, 0);
16183a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          if (opcode2 <= 3) {
1619cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes            opcode << "lsls";
16203a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          } else if (opcode2 <= 7) {
1621cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes            opcode << "lsrs";
16223a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          } else {
1623cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes            opcode << "asrs";
16243a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          }
1625630e77d4648093ce9870c7558d78edea24eab06dElliott Hughes          args << Rd << ", " << rm << ", #" << imm5;
16263a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          break;
16273a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        }
16283a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        case 0xC: case 0xD: case 0xE: case 0xF: {
16293a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          // Add register        - 00 01100 mmm nnn ddd
16303a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          // Sub register        - 00 01101 mmm nnn ddd
16313a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          // Add 3-bit immediate - 00 01110 iii nnn ddd
16323a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          // Sub 3-bit immediate - 00 01111 iii nnn ddd
16333a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          uint16_t imm3_or_Rm = (instr >> 6) & 7;
1634630e77d4648093ce9870c7558d78edea24eab06dElliott Hughes          ThumbRegister Rn(instr, 3);
1635630e77d4648093ce9870c7558d78edea24eab06dElliott Hughes          ThumbRegister Rd(instr, 0);
16363a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          if ((opcode2 & 2) != 0 && imm3_or_Rm == 0) {
1637cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes            opcode << "mov";
16383a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          } else {
16393a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers            if ((opcode2 & 1) == 0) {
1640cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes              opcode << "adds";
16413a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers            } else {
1642cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes              opcode << "subs";
16433a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers            }
16443a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          }
1645630e77d4648093ce9870c7558d78edea24eab06dElliott Hughes          args << Rd << ", " << Rn;
16463a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          if ((opcode2 & 2) == 0) {
1647630e77d4648093ce9870c7558d78edea24eab06dElliott Hughes            ArmRegister Rm(imm3_or_Rm);
1648630e77d4648093ce9870c7558d78edea24eab06dElliott Hughes            args << ", " << Rm;
16493a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          } else if (imm3_or_Rm != 0) {
1650cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes            args << ", #" << imm3_or_Rm;
16513a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          }
16523a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          break;
16533a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        }
16543a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        case 0x10: case 0x11: case 0x12: case 0x13:
16553a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        case 0x14: case 0x15: case 0x16: case 0x17:
16563a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        case 0x18: case 0x19: case 0x1A: case 0x1B:
16573a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        case 0x1C: case 0x1D: case 0x1E: case 0x1F: {
16583a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          // MOVS Rd, #imm8 - 00100 ddd iiiiiiii
16593a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          // CMP  Rn, #imm8 - 00101 nnn iiiiiiii
16603a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          // ADDS Rn, #imm8 - 00110 nnn iiiiiiii
16613a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          // SUBS Rn, #imm8 - 00111 nnn iiiiiiii
1662630e77d4648093ce9870c7558d78edea24eab06dElliott Hughes          ThumbRegister Rn(instr, 8);
16633a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          uint16_t imm8 = instr & 0xFF;
16643a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          switch (opcode2 >> 2) {
1665cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes            case 4: opcode << "movs"; break;
1666cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes            case 5: opcode << "cmp"; break;
1667cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes            case 6: opcode << "adds"; break;
1668cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes            case 7: opcode << "subs"; break;
16693a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          }
1670630e77d4648093ce9870c7558d78edea24eab06dElliott Hughes          args << Rn << ", #" << imm8;
16713a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          break;
16723a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        }
16733a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        default:
16743a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          break;
16753a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      }
1676ad03ef509d5145d74752a0b3f5c87d99db225786Ian Rogers    } else if (opcode1 == 0x10) {
1677ad03ef509d5145d74752a0b3f5c87d99db225786Ian Rogers      // Data-processing
1678ad03ef509d5145d74752a0b3f5c87d99db225786Ian Rogers      uint16_t opcode2 = (instr >> 6) & 0xF;
1679630e77d4648093ce9870c7558d78edea24eab06dElliott Hughes      ThumbRegister rm(instr, 3);
1680630e77d4648093ce9870c7558d78edea24eab06dElliott Hughes      ThumbRegister rdn(instr, 0);
1681ad03ef509d5145d74752a0b3f5c87d99db225786Ian Rogers      opcode << kThumbDataProcessingOperations[opcode2];
1682630e77d4648093ce9870c7558d78edea24eab06dElliott Hughes      args << rdn << ", " << rm;
16833a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    } else if (opcode1 == 0x11) {
16843a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      // Special data instructions and branch and exchange
16853a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      uint16_t opcode2 = (instr >> 6) & 0x0F;
16863a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      switch (opcode2) {
16873a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        case 0x0: case 0x1: case 0x2: case 0x3: {
16883a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          // Add low registers  - 010001 0000 xxxxxx
16893a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          // Add high registers - 010001 0001/001x xxxxxx
16903a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          uint16_t DN = (instr >> 7) & 1;
1691630e77d4648093ce9870c7558d78edea24eab06dElliott Hughes          ArmRegister rm(instr, 3);
16923a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          uint16_t Rdn = instr & 7;
1693630e77d4648093ce9870c7558d78edea24eab06dElliott Hughes          ArmRegister DN_Rdn((DN << 3) | Rdn);
1694cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes          opcode << "add";
1695630e77d4648093ce9870c7558d78edea24eab06dElliott Hughes          args << DN_Rdn << ", " << rm;
16963a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          break;
16973a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        }
16983a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        case 0x8: case 0x9: case 0xA: case 0xB: {
16993a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          // Move low registers  - 010001 1000 xxxxxx
17003a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          // Move high registers - 010001 1001/101x xxxxxx
17013a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          uint16_t DN = (instr >> 7) & 1;
1702630e77d4648093ce9870c7558d78edea24eab06dElliott Hughes          ArmRegister rm(instr, 3);
17033a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          uint16_t Rdn = instr & 7;
1704630e77d4648093ce9870c7558d78edea24eab06dElliott Hughes          ArmRegister DN_Rdn((DN << 3) | Rdn);
1705cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes          opcode << "mov";
1706630e77d4648093ce9870c7558d78edea24eab06dElliott Hughes          args << DN_Rdn << ", " << rm;
17073a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          break;
17083a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        }
17093a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        case 0x5: case 0x6: case 0x7: {
17103a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          // Compare high registers - 010001 0101/011x xxxxxx
17113a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          uint16_t N = (instr >> 7) & 1;
1712630e77d4648093ce9870c7558d78edea24eab06dElliott Hughes          ArmRegister rm(instr, 3);
17133a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          uint16_t Rn = instr & 7;
1714630e77d4648093ce9870c7558d78edea24eab06dElliott Hughes          ArmRegister N_Rn((N << 3) | Rn);
1715cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes          opcode << "cmp";
1716630e77d4648093ce9870c7558d78edea24eab06dElliott Hughes          args << N_Rn << ", " << rm;
17173a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          break;
17183a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        }
17193a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        case 0xC: case 0xD: case 0xE: case 0xF: {
17203a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          // Branch and exchange           - 010001 110x xxxxxx
17213a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          // Branch with link and exchange - 010001 111x xxxxxx
1722630e77d4648093ce9870c7558d78edea24eab06dElliott Hughes          ArmRegister rm(instr, 3);
1723630e77d4648093ce9870c7558d78edea24eab06dElliott Hughes          opcode << ((opcode2 & 0x2) == 0 ? "bx" : "blx");
1724630e77d4648093ce9870c7558d78edea24eab06dElliott Hughes          args << rm;
17253a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          break;
17263a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        }
17273a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        default:
17283a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          break;
17293a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      }
1730eae2691d6120e2f34845eaffec5358d9dd8618ebjeffhao    } else if (opcode1 == 0x12 || opcode1 == 0x13) {  // 01001x
1731a6e95b32d499811bbb37602fc7446a5a0d05b9f8Aart Bik      const uintptr_t lo_adr = reinterpret_cast<intptr_t>(GetDisassemblerOptions()->base_address_);
1732a6e95b32d499811bbb37602fc7446a5a0d05b9f8Aart Bik      const uintptr_t hi_adr = reinterpret_cast<intptr_t>(GetDisassemblerOptions()->end_address_);
1733eae2691d6120e2f34845eaffec5358d9dd8618ebjeffhao      ThumbRegister Rt(instr, 8);
1734eae2691d6120e2f34845eaffec5358d9dd8618ebjeffhao      uint16_t imm8 = instr & 0xFF;
1735eae2691d6120e2f34845eaffec5358d9dd8618ebjeffhao      opcode << "ldr";
1736eae2691d6120e2f34845eaffec5358d9dd8618ebjeffhao      args << Rt << ", [pc, #" << (imm8 << 2) << "]";
1737a6e95b32d499811bbb37602fc7446a5a0d05b9f8Aart Bik      DumpThumb2Literal(args, instr_ptr, lo_adr, hi_adr, /*U*/ 1u, imm8 << 2, kT2LitHexWord);
1738d83bc36185c8b2a763c79fa364b5387faa26c669Ian Rogers    } else if ((opcode1 >= 0x14 && opcode1 <= 0x17) ||  // 0101xx
1739d83bc36185c8b2a763c79fa364b5387faa26c669Ian Rogers               (opcode1 >= 0x18 && opcode1 <= 0x1f) ||  // 011xxx
1740d83bc36185c8b2a763c79fa364b5387faa26c669Ian Rogers               (opcode1 >= 0x20 && opcode1 <= 0x27)) {  // 100xxx
1741d83bc36185c8b2a763c79fa364b5387faa26c669Ian Rogers      // Load/store single data item
1742d83bc36185c8b2a763c79fa364b5387faa26c669Ian Rogers      uint16_t opA = (instr >> 12) & 0xF;
1743d83bc36185c8b2a763c79fa364b5387faa26c669Ian Rogers      if (opA == 0x5) {
1744d83bc36185c8b2a763c79fa364b5387faa26c669Ian Rogers        uint16_t opB = (instr >> 9) & 0x7;
1745d83bc36185c8b2a763c79fa364b5387faa26c669Ian Rogers        ThumbRegister Rm(instr, 6);
1746d83bc36185c8b2a763c79fa364b5387faa26c669Ian Rogers        ThumbRegister Rn(instr, 3);
1747d83bc36185c8b2a763c79fa364b5387faa26c669Ian Rogers        ThumbRegister Rt(instr, 0);
1748df62950e7a32031b82360c407d46a37b94188fbbBrian Carlstrom        switch (opB) {
1749d83bc36185c8b2a763c79fa364b5387faa26c669Ian Rogers          case 0: opcode << "str"; break;
1750d83bc36185c8b2a763c79fa364b5387faa26c669Ian Rogers          case 1: opcode << "strh"; break;
1751d83bc36185c8b2a763c79fa364b5387faa26c669Ian Rogers          case 2: opcode << "strb"; break;
1752d83bc36185c8b2a763c79fa364b5387faa26c669Ian Rogers          case 3: opcode << "ldrsb"; break;
1753d83bc36185c8b2a763c79fa364b5387faa26c669Ian Rogers          case 4: opcode << "ldr"; break;
1754d83bc36185c8b2a763c79fa364b5387faa26c669Ian Rogers          case 5: opcode << "ldrh"; break;
1755d83bc36185c8b2a763c79fa364b5387faa26c669Ian Rogers          case 6: opcode << "ldrb"; break;
1756d83bc36185c8b2a763c79fa364b5387faa26c669Ian Rogers          case 7: opcode << "ldrsh"; break;
1757d83bc36185c8b2a763c79fa364b5387faa26c669Ian Rogers        }
1758d83bc36185c8b2a763c79fa364b5387faa26c669Ian Rogers        args << Rt << ", [" << Rn << ", " << Rm << "]";
1759d83bc36185c8b2a763c79fa364b5387faa26c669Ian Rogers      } else if (opA == 9) {
1760d83bc36185c8b2a763c79fa364b5387faa26c669Ian Rogers        uint16_t opB = (instr >> 11) & 1;
1761d83bc36185c8b2a763c79fa364b5387faa26c669Ian Rogers        ThumbRegister Rt(instr, 8);
1762d83bc36185c8b2a763c79fa364b5387faa26c669Ian Rogers        uint16_t imm8 = instr & 0xFF;
1763d83bc36185c8b2a763c79fa364b5387faa26c669Ian Rogers        opcode << (opB == 0 ? "str" : "ldr");
1764137e88f798857321f4007631fdf052d2830ec2c4Ian Rogers        args << Rt << ", [sp, #" << (imm8 << 2) << "]";
1765d83bc36185c8b2a763c79fa364b5387faa26c669Ian Rogers      } else {
1766d83bc36185c8b2a763c79fa364b5387faa26c669Ian Rogers        uint16_t imm5 = (instr >> 6) & 0x1F;
1767d83bc36185c8b2a763c79fa364b5387faa26c669Ian Rogers        uint16_t opB = (instr >> 11) & 1;
1768d83bc36185c8b2a763c79fa364b5387faa26c669Ian Rogers        ThumbRegister Rn(instr, 3);
1769d83bc36185c8b2a763c79fa364b5387faa26c669Ian Rogers        ThumbRegister Rt(instr, 0);
1770df62950e7a32031b82360c407d46a37b94188fbbBrian Carlstrom        switch (opA) {
1771d83bc36185c8b2a763c79fa364b5387faa26c669Ian Rogers          case 6:
1772d83bc36185c8b2a763c79fa364b5387faa26c669Ian Rogers            imm5 <<= 2;
1773d83bc36185c8b2a763c79fa364b5387faa26c669Ian Rogers            opcode << (opB == 0 ? "str" : "ldr");
1774d83bc36185c8b2a763c79fa364b5387faa26c669Ian Rogers            break;
1775d83bc36185c8b2a763c79fa364b5387faa26c669Ian Rogers          case 7:
1776d83bc36185c8b2a763c79fa364b5387faa26c669Ian Rogers            imm5 <<= 0;
1777d83bc36185c8b2a763c79fa364b5387faa26c669Ian Rogers            opcode << (opB == 0 ? "strb" : "ldrb");
1778d83bc36185c8b2a763c79fa364b5387faa26c669Ian Rogers            break;
1779d83bc36185c8b2a763c79fa364b5387faa26c669Ian Rogers          case 8:
1780d83bc36185c8b2a763c79fa364b5387faa26c669Ian Rogers            imm5 <<= 1;
1781d83bc36185c8b2a763c79fa364b5387faa26c669Ian Rogers            opcode << (opB == 0 ? "strh" : "ldrh");
1782d83bc36185c8b2a763c79fa364b5387faa26c669Ian Rogers            break;
1783d83bc36185c8b2a763c79fa364b5387faa26c669Ian Rogers        }
1784d83bc36185c8b2a763c79fa364b5387faa26c669Ian Rogers        args << Rt << ", [" << Rn << ", #" << imm5 << "]";
1785d83bc36185c8b2a763c79fa364b5387faa26c669Ian Rogers      }
1786eae2691d6120e2f34845eaffec5358d9dd8618ebjeffhao    } else if (opcode1 >= 0x34 && opcode1 <= 0x37) {  // 1101xx
17877761cb669da36384df8c449c864f826ae3db6ac8Ian Rogers      int8_t imm8 = instr & 0xFF;
1788eae2691d6120e2f34845eaffec5358d9dd8618ebjeffhao      uint32_t cond = (instr >> 8) & 0xF;
1789eae2691d6120e2f34845eaffec5358d9dd8618ebjeffhao      opcode << "b";
1790eae2691d6120e2f34845eaffec5358d9dd8618ebjeffhao      DumpCond(opcode, cond);
1791eae2691d6120e2f34845eaffec5358d9dd8618ebjeffhao      DumpBranchTarget(args, instr_ptr + 4, (imm8 << 1));
17929af8940be07c83b150c6922fa341b854daf37455Ian Rogers    } else if ((instr & 0xF800) == 0xA800) {
17939af8940be07c83b150c6922fa341b854daf37455Ian Rogers      // Generate SP-relative address
17949af8940be07c83b150c6922fa341b854daf37455Ian Rogers      ThumbRegister rd(instr, 8);
17959af8940be07c83b150c6922fa341b854daf37455Ian Rogers      int imm8 = instr & 0xFF;
17969af8940be07c83b150c6922fa341b854daf37455Ian Rogers      opcode << "add";
17979af8940be07c83b150c6922fa341b854daf37455Ian Rogers      args << rd << ", sp, #" << (imm8 << 2);
17983a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    } else if ((instr & 0xF000) == 0xB000) {
17993a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      // Miscellaneous 16-bit instructions
18003a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      uint16_t opcode2 = (instr >> 5) & 0x7F;
18013a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      switch (opcode2) {
18023a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: {
18033a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          // Add immediate to SP        - 1011 00000 ii iiiii
18043a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          // Subtract immediate from SP - 1011 00001 ii iiiii
18053a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          int imm7 = instr & 0x7F;
1806630e77d4648093ce9870c7558d78edea24eab06dElliott Hughes          opcode << ((opcode2 & 4) == 0 ? "add" : "sub");
1807cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes          args << "sp, sp, #" << (imm7 << 2);
18083a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          break;
18093a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        }
1810087b2419f432c7d1c32da27c528af4701adb6abdIan Rogers        case 0x08: case 0x09: case 0x0A: case 0x0B:  // 0001xxx
1811ebbc5779756bc73df286254eb62641af2c12b771Ian Rogers        case 0x0C: case 0x0D: case 0x0E: case 0x0F:
1812550191374245cc43089c916a34b292cc4e617dafIan Rogers        case 0x18: case 0x19: case 0x1A: case 0x1B:  // 0011xxx
1813550191374245cc43089c916a34b292cc4e617dafIan Rogers        case 0x1C: case 0x1D: case 0x1E: case 0x1F:
1814ebbc5779756bc73df286254eb62641af2c12b771Ian Rogers        case 0x48: case 0x49: case 0x4A: case 0x4B:  // 1001xxx
1815550191374245cc43089c916a34b292cc4e617dafIan Rogers        case 0x4C: case 0x4D: case 0x4E: case 0x4F:
1816550191374245cc43089c916a34b292cc4e617dafIan Rogers        case 0x58: case 0x59: case 0x5A: case 0x5B:  // 1011xxx
1817550191374245cc43089c916a34b292cc4e617dafIan Rogers        case 0x5C: case 0x5D: case 0x5E: case 0x5F: {
1818087b2419f432c7d1c32da27c528af4701adb6abdIan Rogers          // CBNZ, CBZ
1819087b2419f432c7d1c32da27c528af4701adb6abdIan Rogers          uint16_t op = (instr >> 11) & 1;
1820087b2419f432c7d1c32da27c528af4701adb6abdIan Rogers          uint16_t i = (instr >> 9) & 1;
1821087b2419f432c7d1c32da27c528af4701adb6abdIan Rogers          uint16_t imm5 = (instr >> 3) & 0x1F;
1822630e77d4648093ce9870c7558d78edea24eab06dElliott Hughes          ThumbRegister Rn(instr, 0);
1823087b2419f432c7d1c32da27c528af4701adb6abdIan Rogers          opcode << (op != 0 ? "cbnz" : "cbz");
1824828a07f4b378918673aa56711fa8cf487112659dIan Rogers          uint32_t imm32 = (i << 6) | (imm5 << 1);
1825630e77d4648093ce9870c7558d78edea24eab06dElliott Hughes          args << Rn << ", ";
1826087b2419f432c7d1c32da27c528af4701adb6abdIan Rogers          DumpBranchTarget(args, instr_ptr + 4, imm32);
1827087b2419f432c7d1c32da27c528af4701adb6abdIan Rogers          break;
1828087b2419f432c7d1c32da27c528af4701adb6abdIan Rogers        }
182955d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko        case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
183055d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko        case 0x28: case 0x29: case 0x2A: case 0x2B: case 0x2C: case 0x2D: case 0x2E: case 0x2F: {
183155d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          opcode << "push";
183255d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          args << RegisterList((instr & 0xFF) | ((instr & 0x100) << 6));
183355d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          break;
183455d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko        }
183555d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko        case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67:
183655d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko        case 0x68: case 0x69: case 0x6A: case 0x6B: case 0x6C: case 0x6D: case 0x6E: case 0x6F: {
183755d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          opcode << "pop";
183855d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          args << RegisterList((instr & 0xFF) | ((instr & 0x100) << 7));
183955d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          break;
184055d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko        }
184155d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko        case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: {
184255d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          opcode << "bkpt";
184355d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          args << "#" << (instr & 0xFF);
184455d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko          break;
184555d7c18a1d76eea6d038205ccb9f2d385247f6acVladimir Marko        }
1846a8b4caf7526b6b66a8ae0826bd52c39c66e3c714Vladimir Marko        case 0x50: case 0x51:    // 101000x
1847a8b4caf7526b6b66a8ae0826bd52c39c66e3c714Vladimir Marko        case 0x52: case 0x53:    // 101001x
1848a8b4caf7526b6b66a8ae0826bd52c39c66e3c714Vladimir Marko        case 0x56: case 0x57: {  // 101011x
1849a8b4caf7526b6b66a8ae0826bd52c39c66e3c714Vladimir Marko          uint16_t op = (instr >> 6) & 3;
1850a8b4caf7526b6b66a8ae0826bd52c39c66e3c714Vladimir Marko          opcode << kThumbReverseOperations[op];
1851a8b4caf7526b6b66a8ae0826bd52c39c66e3c714Vladimir Marko          ThumbRegister Rm(instr, 3);
1852a8b4caf7526b6b66a8ae0826bd52c39c66e3c714Vladimir Marko          ThumbRegister Rd(instr, 0);
1853a8b4caf7526b6b66a8ae0826bd52c39c66e3c714Vladimir Marko          args << Rd << ", " << Rm;
1854a8b4caf7526b6b66a8ae0826bd52c39c66e3c714Vladimir Marko          break;
1855a8b4caf7526b6b66a8ae0826bd52c39c66e3c714Vladimir Marko        }
185640627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers        case 0x78: case 0x79: case 0x7A: case 0x7B:  // 1111xxx
185740627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers        case 0x7C: case 0x7D: case 0x7E: case 0x7F: {
185840627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers          // If-Then, and hints
185940627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers          uint16_t opA = (instr >> 4) & 0xF;
186040627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers          uint16_t opB = instr & 0xF;
186140627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers          if (opB == 0) {
186240627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers            switch (opA) {
1863cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes              case 0: opcode << "nop"; break;
1864cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes              case 1: opcode << "yield"; break;
1865cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes              case 2: opcode << "wfe";  break;
1866cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes              case 3: opcode << "sev"; break;
186740627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers              default: break;
186840627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers            }
186940627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers          } else {
1870105afd2bd8f9f0ddfcfcb4b8db9f356ee82ae8cdElliott Hughes            uint32_t first_cond = opA;
1871105afd2bd8f9f0ddfcfcb4b8db9f356ee82ae8cdElliott Hughes            uint32_t mask = opB;
1872cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes            opcode << "it";
1873105afd2bd8f9f0ddfcfcb4b8db9f356ee82ae8cdElliott Hughes
1874105afd2bd8f9f0ddfcfcb4b8db9f356ee82ae8cdElliott Hughes            // Flesh out the base "it" opcode with the specific collection of 't's and 'e's,
1875105afd2bd8f9f0ddfcfcb4b8db9f356ee82ae8cdElliott Hughes            // and store up the actual condition codes we'll want to add to the next few opcodes.
1876105afd2bd8f9f0ddfcfcb4b8db9f356ee82ae8cdElliott Hughes            size_t count = 3 - CTZ(mask);
18777934ac288acfb2552bb0b06ec1f61e5820d924a4Brian Carlstrom            it_conditions_.resize(count + 2);  // Plus the implicit 't', plus the "" for the IT itself.
1878105afd2bd8f9f0ddfcfcb4b8db9f356ee82ae8cdElliott Hughes            for (size_t i = 0; i < count; ++i) {
1879105afd2bd8f9f0ddfcfcb4b8db9f356ee82ae8cdElliott Hughes              bool positive_cond = ((first_cond & 1) != 0);
1880105afd2bd8f9f0ddfcfcb4b8db9f356ee82ae8cdElliott Hughes              bool positive_mask = ((mask & (1 << (3 - i))) != 0);
1881105afd2bd8f9f0ddfcfcb4b8db9f356ee82ae8cdElliott Hughes              if (positive_mask == positive_cond) {
1882105afd2bd8f9f0ddfcfcb4b8db9f356ee82ae8cdElliott Hughes                opcode << 't';
1883105afd2bd8f9f0ddfcfcb4b8db9f356ee82ae8cdElliott Hughes                it_conditions_[i] = kConditionCodeNames[first_cond];
1884105afd2bd8f9f0ddfcfcb4b8db9f356ee82ae8cdElliott Hughes              } else {
1885105afd2bd8f9f0ddfcfcb4b8db9f356ee82ae8cdElliott Hughes                opcode << 'e';
1886105afd2bd8f9f0ddfcfcb4b8db9f356ee82ae8cdElliott Hughes                it_conditions_[i] = kConditionCodeNames[first_cond ^ 1];
1887105afd2bd8f9f0ddfcfcb4b8db9f356ee82ae8cdElliott Hughes              }
1888105afd2bd8f9f0ddfcfcb4b8db9f356ee82ae8cdElliott Hughes            }
18897934ac288acfb2552bb0b06ec1f61e5820d924a4Brian Carlstrom            it_conditions_[count] = kConditionCodeNames[first_cond];  // The implicit 't'.
1890105afd2bd8f9f0ddfcfcb4b8db9f356ee82ae8cdElliott Hughes
18917934ac288acfb2552bb0b06ec1f61e5820d924a4Brian Carlstrom            it_conditions_[count + 1] = "";  // No condition code for the IT itself...
18927934ac288acfb2552bb0b06ec1f61e5820d924a4Brian Carlstrom            DumpCond(args, first_cond);  // ...because it's considered an argument.
189340627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers          }
189440627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers          break;
189540627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers        }
18963a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        default:
18973a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          break;
18983a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      }
18993a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    } else if (((instr & 0xF000) == 0x5000) || ((instr & 0xE000) == 0x6000) ||
19003a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        ((instr & 0xE000) == 0x8000)) {
19013a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      // Load/store single data item
19023a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      uint16_t opA = instr >> 12;
19037934ac288acfb2552bb0b06ec1f61e5820d924a4Brian Carlstrom      // uint16_t opB = (instr >> 9) & 7;
19043a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      switch (opA) {
19053a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        case 0x6: {
190628fa76d17d741238da86dbdb47f721ae97c9eac8Elliott Hughes          // STR Rt, [Rn, #imm] - 01100 iiiii nnn ttt
190728fa76d17d741238da86dbdb47f721ae97c9eac8Elliott Hughes          // LDR Rt, [Rn, #imm] - 01101 iiiii nnn ttt
19083a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          uint16_t imm5 = (instr >> 6) & 0x1F;
1909630e77d4648093ce9870c7558d78edea24eab06dElliott Hughes          ThumbRegister Rn(instr, 3);
191028fa76d17d741238da86dbdb47f721ae97c9eac8Elliott Hughes          ThumbRegister Rt(instr, 0);
1911630e77d4648093ce9870c7558d78edea24eab06dElliott Hughes          opcode << ((instr & 0x800) == 0 ? "str" : "ldr");
1912630e77d4648093ce9870c7558d78edea24eab06dElliott Hughes          args << Rt << ", [" << Rn << ", #" << (imm5 << 2) << "]";
19133a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          break;
19143a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        }
19153a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        case 0x9: {
19163a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          // STR Rt, [SP, #imm] - 01100 ttt iiiiiiii
19173a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          // LDR Rt, [SP, #imm] - 01101 ttt iiiiiiii
19183a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          uint16_t imm8 = instr & 0xFF;
1919630e77d4648093ce9870c7558d78edea24eab06dElliott Hughes          ThumbRegister Rt(instr, 8);
1920630e77d4648093ce9870c7558d78edea24eab06dElliott Hughes          opcode << ((instr & 0x800) == 0 ? "str" : "ldr");
1921630e77d4648093ce9870c7558d78edea24eab06dElliott Hughes          args << Rt << ", [sp, #" << (imm8 << 2) << "]";
19223a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          break;
19233a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        }
19243a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers        default:
19253a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers          break;
19263a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers      }
192740627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers    } else if (opcode1 == 0x38 || opcode1 == 0x39) {
192840627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers      uint16_t imm11 = instr & 0x7FFF;
192940627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers      int32_t imm32 = imm11 << 1;
193040627dbd27b3c9e2cf32768882d9859ce71ef015Ian Rogers      imm32 = (imm32 << 20) >> 20;  // sign extend 12 bit immediate
1931cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes      opcode << "b";
1932cbf0b61f5415e96a76284deff87e7cb9aba022b9Elliott Hughes      DumpBranchTarget(args, instr_ptr + 4, imm32);
19333a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers    }
1934105afd2bd8f9f0ddfcfcb4b8db9f356ee82ae8cdElliott Hughes
1935105afd2bd8f9f0ddfcfcb4b8db9f356ee82ae8cdElliott Hughes    // Apply any IT-block conditions to the opcode if necessary.
1936105afd2bd8f9f0ddfcfcb4b8db9f356ee82ae8cdElliott Hughes    if (!it_conditions_.empty()) {
1937105afd2bd8f9f0ddfcfcb4b8db9f356ee82ae8cdElliott Hughes      opcode << it_conditions_.back();
1938105afd2bd8f9f0ddfcfcb4b8db9f356ee82ae8cdElliott Hughes      it_conditions_.pop_back();
1939105afd2bd8f9f0ddfcfcb4b8db9f356ee82ae8cdElliott Hughes    }
1940105afd2bd8f9f0ddfcfcb4b8db9f356ee82ae8cdElliott Hughes
19412cbaccb67e22c0b313a9785bfc65bcb4b25d0676Brian Carlstrom    os << FormatInstructionPointer(instr_ptr)
19422cbaccb67e22c0b313a9785bfc65bcb4b25d0676Brian Carlstrom       << StringPrintf(": %04x    \t%-7s ", instr, opcode.str().c_str())
19432cbaccb67e22c0b313a9785bfc65bcb4b25d0676Brian Carlstrom       << args.str() << '\n';
19443a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  }
19453a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers  return 2;
19463a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers}
19473a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers
19483a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers}  // namespace arm
19493a5c1ce3f11805a3382046f699c8fb1410a602b3Ian Rogers}  // namespace art
1950