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