| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 1 | //===-- EmulateInstructionARM.cpp -------------------------------*- C++ -*-===// | 
|  | 2 | // | 
|  | 3 | //                     The LLVM Compiler Infrastructure | 
|  | 4 | // | 
|  | 5 | // This file is distributed under the University of Illinois Open Source | 
|  | 6 | // License. See LICENSE.TXT for details. | 
|  | 7 | // | 
|  | 8 | //===----------------------------------------------------------------------===// | 
|  | 9 |  | 
| Caroline Tice | fa17220 | 2011-02-11 22:49:54 +0000 | [diff] [blame] | 10 | #include <stdlib.h> | 
|  | 11 |  | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 12 | #include "EmulateInstructionARM.h" | 
| Caroline Tice | 6b8d3b5 | 2011-04-19 23:30:03 +0000 | [diff] [blame] | 13 | #include "EmulationStateARM.h" | 
| Greg Clayton | 395fc33 | 2011-02-15 21:59:32 +0000 | [diff] [blame] | 14 | #include "lldb/Core/ArchSpec.h" | 
| Caroline Tice | 080bf61 | 2011-04-05 18:46:00 +0000 | [diff] [blame] | 15 | #include "lldb/Core/Address.h" | 
| Greg Clayton | 8482ded | 2011-02-01 00:04:43 +0000 | [diff] [blame] | 16 | #include "lldb/Core/ConstString.h" | 
| Caroline Tice | 080bf61 | 2011-04-05 18:46:00 +0000 | [diff] [blame] | 17 | #include "lldb/Core/PluginManager.h" | 
| Caroline Tice | 6b8d3b5 | 2011-04-19 23:30:03 +0000 | [diff] [blame] | 18 | #include "lldb/Core/Stream.h" | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 19 | #include "lldb/Symbol/UnwindPlan.h" | 
| Greg Clayton | 8482ded | 2011-02-01 00:04:43 +0000 | [diff] [blame] | 20 |  | 
| Greg Clayton | f29a08f | 2011-02-09 17:41:27 +0000 | [diff] [blame] | 21 | #include "Plugins/Process/Utility/ARMDefines.h" | 
|  | 22 | #include "Plugins/Process/Utility/ARMUtils.h" | 
|  | 23 | #include "Utility/ARM_DWARF_Registers.h" | 
|  | 24 |  | 
| Johnny Chen | 9b8d783 | 2011-02-02 01:13:56 +0000 | [diff] [blame] | 25 | #include "llvm/Support/MathExtras.h" // for SignExtend32 template function | 
| Johnny Chen | 9307047 | 2011-02-04 23:02:47 +0000 | [diff] [blame] | 26 | // and CountTrailingZeros_32 function | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 27 |  | 
|  | 28 | using namespace lldb; | 
|  | 29 | using namespace lldb_private; | 
|  | 30 |  | 
| Johnny Chen | e97c0d5 | 2011-02-18 19:32:20 +0000 | [diff] [blame] | 31 | // Convenient macro definitions. | 
| Greg Clayton | b344843 | 2011-03-24 21:19:54 +0000 | [diff] [blame] | 32 | #define APSR_C Bit32(m_opcode_cpsr, CPSR_C_POS) | 
|  | 33 | #define APSR_V Bit32(m_opcode_cpsr, CPSR_V_POS) | 
| Johnny Chen | e97c0d5 | 2011-02-18 19:32:20 +0000 | [diff] [blame] | 34 |  | 
| Caroline Tice | f55261f | 2011-02-18 22:24:22 +0000 | [diff] [blame] | 35 | #define AlignPC(pc_val) (pc_val & 0xFFFFFFFC) | 
|  | 36 |  | 
| Johnny Chen | 0e00af2 | 2011-02-10 19:40:42 +0000 | [diff] [blame] | 37 | //---------------------------------------------------------------------- | 
|  | 38 | // | 
|  | 39 | // ITSession implementation | 
|  | 40 | // | 
|  | 41 | //---------------------------------------------------------------------- | 
|  | 42 |  | 
| Johnny Chen | 9307047 | 2011-02-04 23:02:47 +0000 | [diff] [blame] | 43 | // A8.6.50 | 
|  | 44 | // Valid return values are {1, 2, 3, 4}, with 0 signifying an error condition. | 
| Greg Clayton | 04d397c | 2011-05-23 18:04:09 +0000 | [diff] [blame] | 45 | static uint32_t | 
|  | 46 | CountITSize (uint32_t ITMask) { | 
| Johnny Chen | 9307047 | 2011-02-04 23:02:47 +0000 | [diff] [blame] | 47 | // First count the trailing zeros of the IT mask. | 
| Greg Clayton | 04d397c | 2011-05-23 18:04:09 +0000 | [diff] [blame] | 48 | uint32_t TZ = llvm::CountTrailingZeros_32(ITMask); | 
| Johnny Chen | 9307047 | 2011-02-04 23:02:47 +0000 | [diff] [blame] | 49 | if (TZ > 3) | 
|  | 50 | { | 
|  | 51 | printf("Encoding error: IT Mask '0000'\n"); | 
|  | 52 | return 0; | 
|  | 53 | } | 
|  | 54 | return (4 - TZ); | 
|  | 55 | } | 
|  | 56 |  | 
|  | 57 | // Init ITState.  Note that at least one bit is always 1 in mask. | 
| Greg Clayton | 04d397c | 2011-05-23 18:04:09 +0000 | [diff] [blame] | 58 | bool ITSession::InitIT(uint32_t bits7_0) | 
| Johnny Chen | 9307047 | 2011-02-04 23:02:47 +0000 | [diff] [blame] | 59 | { | 
|  | 60 | ITCounter = CountITSize(Bits32(bits7_0, 3, 0)); | 
|  | 61 | if (ITCounter == 0) | 
|  | 62 | return false; | 
|  | 63 |  | 
|  | 64 | // A8.6.50 IT | 
|  | 65 | unsigned short FirstCond = Bits32(bits7_0, 7, 4); | 
|  | 66 | if (FirstCond == 0xF) | 
|  | 67 | { | 
|  | 68 | printf("Encoding error: IT FirstCond '1111'\n"); | 
|  | 69 | return false; | 
|  | 70 | } | 
|  | 71 | if (FirstCond == 0xE && ITCounter != 1) | 
|  | 72 | { | 
|  | 73 | printf("Encoding error: IT FirstCond '1110' && Mask != '1000'\n"); | 
|  | 74 | return false; | 
|  | 75 | } | 
|  | 76 |  | 
|  | 77 | ITState = bits7_0; | 
|  | 78 | return true; | 
|  | 79 | } | 
|  | 80 |  | 
|  | 81 | // Update ITState if necessary. | 
|  | 82 | void ITSession::ITAdvance() | 
|  | 83 | { | 
| Greg Clayton | e1f47bb | 2011-06-02 22:23:35 +0000 | [diff] [blame] | 84 | //assert(ITCounter); | 
| Johnny Chen | 9307047 | 2011-02-04 23:02:47 +0000 | [diff] [blame] | 85 | --ITCounter; | 
|  | 86 | if (ITCounter == 0) | 
|  | 87 | ITState = 0; | 
|  | 88 | else | 
|  | 89 | { | 
|  | 90 | unsigned short NewITState4_0 = Bits32(ITState, 4, 0) << 1; | 
|  | 91 | SetBits32(ITState, 4, 0, NewITState4_0); | 
|  | 92 | } | 
|  | 93 | } | 
|  | 94 |  | 
|  | 95 | // Return true if we're inside an IT Block. | 
|  | 96 | bool ITSession::InITBlock() | 
|  | 97 | { | 
|  | 98 | return ITCounter != 0; | 
|  | 99 | } | 
|  | 100 |  | 
| Johnny Chen | c315f86 | 2011-02-05 00:46:10 +0000 | [diff] [blame] | 101 | // Return true if we're the last instruction inside an IT Block. | 
|  | 102 | bool ITSession::LastInITBlock() | 
|  | 103 | { | 
|  | 104 | return ITCounter == 1; | 
|  | 105 | } | 
|  | 106 |  | 
| Johnny Chen | 9307047 | 2011-02-04 23:02:47 +0000 | [diff] [blame] | 107 | // Get condition bits for the current thumb instruction. | 
|  | 108 | uint32_t ITSession::GetCond() | 
|  | 109 | { | 
| Johnny Chen | c315f86 | 2011-02-05 00:46:10 +0000 | [diff] [blame] | 110 | if (InITBlock()) | 
|  | 111 | return Bits32(ITState, 7, 4); | 
|  | 112 | else | 
|  | 113 | return COND_AL; | 
| Johnny Chen | 9307047 | 2011-02-04 23:02:47 +0000 | [diff] [blame] | 114 | } | 
|  | 115 |  | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 116 | // ARM constants used during decoding | 
|  | 117 | #define REG_RD          0 | 
|  | 118 | #define LDM_REGLIST     1 | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 119 | #define SP_REG          13 | 
|  | 120 | #define LR_REG          14 | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 121 | #define PC_REG          15 | 
|  | 122 | #define PC_REGLIST_BIT  0x8000 | 
|  | 123 |  | 
| Johnny Chen | 251af6a | 2011-01-21 22:47:25 +0000 | [diff] [blame] | 124 | #define ARMv4     (1u << 0) | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 125 | #define ARMv4T    (1u << 1) | 
|  | 126 | #define ARMv5T    (1u << 2) | 
|  | 127 | #define ARMv5TE   (1u << 3) | 
|  | 128 | #define ARMv5TEJ  (1u << 4) | 
| Johnny Chen | 251af6a | 2011-01-21 22:47:25 +0000 | [diff] [blame] | 129 | #define ARMv6     (1u << 5) | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 130 | #define ARMv6K    (1u << 6) | 
|  | 131 | #define ARMv6T2   (1u << 7) | 
| Johnny Chen | 251af6a | 2011-01-21 22:47:25 +0000 | [diff] [blame] | 132 | #define ARMv7     (1u << 8) | 
| Johnny Chen | 60c0d62 | 2011-01-25 23:49:39 +0000 | [diff] [blame] | 133 | #define ARMv8     (1u << 9) | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 134 | #define ARMvAll   (0xffffffffu) | 
|  | 135 |  | 
| Johnny Chen | 9b8d783 | 2011-02-02 01:13:56 +0000 | [diff] [blame] | 136 | #define ARMV4T_ABOVE  (ARMv4T|ARMv5T|ARMv5TE|ARMv5TEJ|ARMv6|ARMv6K|ARMv6T2|ARMv7|ARMv8) | 
|  | 137 | #define ARMV5_ABOVE   (ARMv5T|ARMv5TE|ARMv5TEJ|ARMv6|ARMv6K|ARMv6T2|ARMv7|ARMv8) | 
| Caroline Tice | 1697dd7 | 2011-03-30 17:11:45 +0000 | [diff] [blame] | 138 | #define ARMV5TE_ABOVE (ARMv5TE|ARMv5TEJ|ARMv6|ARMv6K|ARMv6T2|ARMv7|ARMv8) | 
| Johnny Chen | 59e6ab7 | 2011-02-24 21:01:20 +0000 | [diff] [blame] | 139 | #define ARMV5J_ABOVE  (ARMv5TEJ|ARMv6|ARMv6K|ARMv6T2|ARMv7|ARMv8) | 
| Caroline Tice | 6bf6516 | 2011-03-03 17:42:58 +0000 | [diff] [blame] | 140 | #define ARMV6_ABOVE   (ARMv6|ARMv6K|ARMv6T2|ARMv7|ARMv8) | 
| Johnny Chen | 9b8d783 | 2011-02-02 01:13:56 +0000 | [diff] [blame] | 141 | #define ARMV6T2_ABOVE (ARMv6T2|ARMv7|ARMv8) | 
| Greg Clayton | 04d397c | 2011-05-23 18:04:09 +0000 | [diff] [blame] | 142 | #define ARMV7_ABOVE   (ARMv7|ARMv8) | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 143 |  | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 144 | #define No_VFP  0 | 
|  | 145 | #define VFPv1   (1u << 1) | 
|  | 146 | #define VFPv2   (1u << 2) | 
|  | 147 | #define VFPv3   (1u << 3) | 
|  | 148 | #define AdvancedSIMD (1u << 4) | 
|  | 149 |  | 
|  | 150 | #define VFPv1_ABOVE (VFPv1 | VFPv2 | VFPv3 | AdvancedSIMD) | 
|  | 151 | #define VFPv2_ABOVE (VFPv2 | VFPv3 | AdvancedSIMD) | 
|  | 152 | #define VFPv2v3     (VFPv2 | VFPv3) | 
|  | 153 |  | 
| Johnny Chen | 0e00af2 | 2011-02-10 19:40:42 +0000 | [diff] [blame] | 154 | //---------------------------------------------------------------------- | 
|  | 155 | // | 
|  | 156 | // EmulateInstructionARM implementation | 
|  | 157 | // | 
|  | 158 | //---------------------------------------------------------------------- | 
|  | 159 |  | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 160 | void | 
|  | 161 | EmulateInstructionARM::Initialize () | 
| Johnny Chen | 7dc60e1 | 2011-01-24 19:46:32 +0000 | [diff] [blame] | 162 | { | 
| Caroline Tice | 080bf61 | 2011-04-05 18:46:00 +0000 | [diff] [blame] | 163 | PluginManager::RegisterPlugin (GetPluginNameStatic (), | 
|  | 164 | GetPluginDescriptionStatic (), | 
|  | 165 | CreateInstance); | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 166 | } | 
| Johnny Chen | 7dc60e1 | 2011-01-24 19:46:32 +0000 | [diff] [blame] | 167 |  | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 168 | void | 
|  | 169 | EmulateInstructionARM::Terminate () | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 170 | { | 
| Caroline Tice | 080bf61 | 2011-04-05 18:46:00 +0000 | [diff] [blame] | 171 | PluginManager::UnregisterPlugin (CreateInstance); | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 172 | } | 
|  | 173 |  | 
| Caroline Tice | 080bf61 | 2011-04-05 18:46:00 +0000 | [diff] [blame] | 174 | const char * | 
|  | 175 | EmulateInstructionARM::GetPluginNameStatic () | 
|  | 176 | { | 
|  | 177 | return "lldb.emulate-instruction.arm"; | 
|  | 178 | } | 
|  | 179 |  | 
|  | 180 | const char * | 
|  | 181 | EmulateInstructionARM::GetPluginDescriptionStatic () | 
|  | 182 | { | 
|  | 183 | return "Emulate instructions for the ARM architecture."; | 
|  | 184 | } | 
|  | 185 |  | 
|  | 186 | EmulateInstruction * | 
| Greg Clayton | 888a733 | 2011-04-26 04:39:08 +0000 | [diff] [blame] | 187 | EmulateInstructionARM::CreateInstance (const ArchSpec &arch, InstructionType inst_type) | 
| Caroline Tice | 080bf61 | 2011-04-05 18:46:00 +0000 | [diff] [blame] | 188 | { | 
| Greg Clayton | 888a733 | 2011-04-26 04:39:08 +0000 | [diff] [blame] | 189 | if (EmulateInstructionARM::SupportsEmulatingIntructionsOfTypeStatic(inst_type)) | 
| Caroline Tice | 080bf61 | 2011-04-05 18:46:00 +0000 | [diff] [blame] | 190 | { | 
| Greg Clayton | 888a733 | 2011-04-26 04:39:08 +0000 | [diff] [blame] | 191 | if (arch.GetTriple().getArch() == llvm::Triple::arm) | 
|  | 192 | { | 
|  | 193 | std::auto_ptr<EmulateInstructionARM> emulate_insn_ap (new EmulateInstructionARM (arch)); | 
|  | 194 |  | 
|  | 195 | if (emulate_insn_ap.get()) | 
|  | 196 | return emulate_insn_ap.release(); | 
|  | 197 | } | 
|  | 198 | else if (arch.GetTriple().getArch() == llvm::Triple::thumb) | 
|  | 199 | { | 
|  | 200 | std::auto_ptr<EmulateInstructionARM> emulate_insn_ap (new EmulateInstructionARM (arch)); | 
|  | 201 |  | 
|  | 202 | if (emulate_insn_ap.get()) | 
|  | 203 | return emulate_insn_ap.release(); | 
|  | 204 | } | 
| Caroline Tice | 080bf61 | 2011-04-05 18:46:00 +0000 | [diff] [blame] | 205 | } | 
|  | 206 |  | 
|  | 207 | return NULL; | 
|  | 208 | } | 
|  | 209 |  | 
|  | 210 | bool | 
|  | 211 | EmulateInstructionARM::SetTargetTriple (const ArchSpec &arch) | 
|  | 212 | { | 
|  | 213 | if (arch.GetTriple().getArch () == llvm::Triple::arm) | 
|  | 214 | return true; | 
|  | 215 | else if (arch.GetTriple().getArch () == llvm::Triple::thumb) | 
|  | 216 | return true; | 
|  | 217 |  | 
|  | 218 | return false; | 
|  | 219 | } | 
|  | 220 |  | 
| Caroline Tice | fa17220 | 2011-02-11 22:49:54 +0000 | [diff] [blame] | 221 | // Write "bits (32) UNKNOWN" to memory address "address".  Helper function for many ARM instructions. | 
|  | 222 | bool | 
|  | 223 | EmulateInstructionARM::WriteBits32UnknownToMemory (addr_t address) | 
|  | 224 | { | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 225 | EmulateInstruction::Context context; | 
|  | 226 | context.type = EmulateInstruction::eContextWriteMemoryRandomBits; | 
|  | 227 | context.SetNoArgs (); | 
| Caroline Tice | fa17220 | 2011-02-11 22:49:54 +0000 | [diff] [blame] | 228 |  | 
|  | 229 | uint32_t random_data = rand (); | 
|  | 230 | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  | 231 |  | 
| Caroline Tice | cc96eb5 | 2011-02-17 19:20:40 +0000 | [diff] [blame] | 232 | if (!MemAWrite (context, address, random_data, addr_byte_size)) | 
| Caroline Tice | fa17220 | 2011-02-11 22:49:54 +0000 | [diff] [blame] | 233 | return false; | 
|  | 234 |  | 
|  | 235 | return true; | 
|  | 236 | } | 
|  | 237 |  | 
| Caroline Tice | 713c266 | 2011-02-11 17:59:55 +0000 | [diff] [blame] | 238 | // Write "bits (32) UNKNOWN" to register n.  Helper function for many ARM instructions. | 
|  | 239 | bool | 
|  | 240 | EmulateInstructionARM::WriteBits32Unknown (int n) | 
|  | 241 | { | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 242 | EmulateInstruction::Context context; | 
|  | 243 | context.type = EmulateInstruction::eContextWriteRegisterRandomBits; | 
|  | 244 | context.SetNoArgs (); | 
| Caroline Tice | 713c266 | 2011-02-11 17:59:55 +0000 | [diff] [blame] | 245 |  | 
| Johnny Chen | 62ff6f5 | 2011-02-11 18:11:22 +0000 | [diff] [blame] | 246 | bool success; | 
| Caroline Tice | 713c266 | 2011-02-11 17:59:55 +0000 | [diff] [blame] | 247 | uint32_t data = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success); | 
|  | 248 |  | 
|  | 249 | if (!success) | 
|  | 250 | return false; | 
|  | 251 |  | 
|  | 252 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, data)) | 
|  | 253 | return false; | 
|  | 254 |  | 
|  | 255 | return true; | 
|  | 256 | } | 
|  | 257 |  | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 258 | bool | 
|  | 259 | EmulateInstructionARM::GetRegisterInfo (uint32_t reg_kind, uint32_t reg_num, RegisterInfo ®_info) | 
|  | 260 | { | 
|  | 261 | if (reg_kind == eRegisterKindGeneric) | 
|  | 262 | { | 
|  | 263 | switch (reg_num) | 
|  | 264 | { | 
|  | 265 | case LLDB_REGNUM_GENERIC_PC:    reg_kind = eRegisterKindDWARF; reg_num = dwarf_pc; break; | 
|  | 266 | case LLDB_REGNUM_GENERIC_SP:    reg_kind = eRegisterKindDWARF; reg_num = dwarf_sp; break; | 
|  | 267 | case LLDB_REGNUM_GENERIC_FP:    reg_kind = eRegisterKindDWARF; reg_num = dwarf_r7; break; | 
|  | 268 | case LLDB_REGNUM_GENERIC_RA:    reg_kind = eRegisterKindDWARF; reg_num = dwarf_lr; break; | 
|  | 269 | case LLDB_REGNUM_GENERIC_FLAGS: reg_kind = eRegisterKindDWARF; reg_num = dwarf_cpsr; break; | 
|  | 270 | default: return false; | 
|  | 271 | } | 
|  | 272 | } | 
|  | 273 |  | 
|  | 274 | if (reg_kind == eRegisterKindDWARF) | 
|  | 275 | return GetARMDWARFRegisterInfo(reg_num, reg_info); | 
|  | 276 | return false; | 
|  | 277 | } | 
|  | 278 |  | 
| Greg Clayton | 04d397c | 2011-05-23 18:04:09 +0000 | [diff] [blame] | 279 | uint32_t | 
|  | 280 | EmulateInstructionARM::GetFramePointerRegisterNumber () const | 
|  | 281 | { | 
|  | 282 | if (m_opcode_mode == eModeThumb || m_arch.GetTriple().getOS() == llvm::Triple::Darwin) | 
|  | 283 | return 7; | 
|  | 284 | else | 
|  | 285 | return 11; | 
|  | 286 | } | 
|  | 287 |  | 
|  | 288 | uint32_t | 
|  | 289 | EmulateInstructionARM::GetFramePointerDWARFRegisterNumber () const | 
|  | 290 | { | 
|  | 291 | if (m_opcode_mode == eModeThumb || m_arch.GetTriple().getOS() == llvm::Triple::Darwin) | 
|  | 292 | return dwarf_r7; | 
|  | 293 | else | 
|  | 294 | return dwarf_r11; | 
|  | 295 | } | 
|  | 296 |  | 
| Johnny Chen | 08c25e8 | 2011-01-31 18:02:28 +0000 | [diff] [blame] | 297 | // Push Multiple Registers stores multiple registers to the stack, storing to | 
|  | 298 | // consecutive memory locations ending just below the address in SP, and updates | 
|  | 299 | // SP to point to the start of the stored data. | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 300 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 301 | EmulateInstructionARM::EmulatePUSH (const uint32_t opcode, const ARMEncoding encoding) | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 302 | { | 
|  | 303 | #if 0 | 
|  | 304 | // ARM pseudo code... | 
|  | 305 | if (ConditionPassed()) | 
|  | 306 | { | 
|  | 307 | EncodingSpecificOperations(); | 
|  | 308 | NullCheckIfThumbEE(13); | 
|  | 309 | address = SP - 4*BitCount(registers); | 
|  | 310 |  | 
|  | 311 | for (i = 0 to 14) | 
|  | 312 | { | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 313 | if (registers<i> == '1') | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 314 | { | 
|  | 315 | if i == 13 && i != LowestSetBit(registers) // Only possible for encoding A1 | 
|  | 316 | MemA[address,4] = bits(32) UNKNOWN; | 
|  | 317 | else | 
|  | 318 | MemA[address,4] = R[i]; | 
|  | 319 | address = address + 4; | 
|  | 320 | } | 
|  | 321 | } | 
|  | 322 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 323 | if (registers<15> == '1') // Only possible for encoding A1 or A2 | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 324 | MemA[address,4] = PCStoreValue(); | 
|  | 325 |  | 
|  | 326 | SP = SP - 4*BitCount(registers); | 
|  | 327 | } | 
|  | 328 | #endif | 
|  | 329 |  | 
| Greg Clayton | 107e53d | 2011-07-06 04:07:21 +0000 | [diff] [blame] | 330 | bool conditional = false; | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 331 | bool success = false; | 
| Greg Clayton | 107e53d | 2011-07-06 04:07:21 +0000 | [diff] [blame] | 332 | if (ConditionPassed(opcode, &conditional)) | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 333 | { | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 334 | const uint32_t addr_byte_size = GetAddressByteSize(); | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 335 | const addr_t sp = ReadCoreReg (SP_REG, &success); | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 336 | if (!success) | 
|  | 337 | return false; | 
| Johnny Chen | 3c75c76 | 2011-01-22 00:47:08 +0000 | [diff] [blame] | 338 | uint32_t registers = 0; | 
| Johnny Chen | 91d9986 | 2011-01-25 19:07:04 +0000 | [diff] [blame] | 339 | uint32_t Rt; // the source register | 
| Johnny Chen | 3c75c76 | 2011-01-22 00:47:08 +0000 | [diff] [blame] | 340 | switch (encoding) { | 
| Johnny Chen | aedde1c | 2011-01-24 20:38:45 +0000 | [diff] [blame] | 341 | case eEncodingT1: | 
| Johnny Chen | 108d5aa | 2011-01-26 01:00:55 +0000 | [diff] [blame] | 342 | registers = Bits32(opcode, 7, 0); | 
| Johnny Chen | aedde1c | 2011-01-24 20:38:45 +0000 | [diff] [blame] | 343 | // The M bit represents LR. | 
| Johnny Chen | bd59990 | 2011-02-10 21:39:01 +0000 | [diff] [blame] | 344 | if (Bit32(opcode, 8)) | 
| Johnny Chen | ef85e91 | 2011-01-31 23:07:40 +0000 | [diff] [blame] | 345 | registers |= (1u << 14); | 
| Johnny Chen | aedde1c | 2011-01-24 20:38:45 +0000 | [diff] [blame] | 346 | // if BitCount(registers) < 1 then UNPREDICTABLE; | 
|  | 347 | if (BitCount(registers) < 1) | 
|  | 348 | return false; | 
|  | 349 | break; | 
| Johnny Chen | 7dc60e1 | 2011-01-24 19:46:32 +0000 | [diff] [blame] | 350 | case eEncodingT2: | 
|  | 351 | // Ignore bits 15 & 13. | 
| Johnny Chen | 108d5aa | 2011-01-26 01:00:55 +0000 | [diff] [blame] | 352 | registers = Bits32(opcode, 15, 0) & ~0xa000; | 
| Johnny Chen | 7dc60e1 | 2011-01-24 19:46:32 +0000 | [diff] [blame] | 353 | // if BitCount(registers) < 2 then UNPREDICTABLE; | 
|  | 354 | if (BitCount(registers) < 2) | 
|  | 355 | return false; | 
|  | 356 | break; | 
|  | 357 | case eEncodingT3: | 
| Johnny Chen | 108d5aa | 2011-01-26 01:00:55 +0000 | [diff] [blame] | 358 | Rt = Bits32(opcode, 15, 12); | 
| Johnny Chen | 7dc60e1 | 2011-01-24 19:46:32 +0000 | [diff] [blame] | 359 | // if BadReg(t) then UNPREDICTABLE; | 
| Johnny Chen | 91d9986 | 2011-01-25 19:07:04 +0000 | [diff] [blame] | 360 | if (BadReg(Rt)) | 
| Johnny Chen | 7dc60e1 | 2011-01-24 19:46:32 +0000 | [diff] [blame] | 361 | return false; | 
| Johnny Chen | 91d9986 | 2011-01-25 19:07:04 +0000 | [diff] [blame] | 362 | registers = (1u << Rt); | 
| Johnny Chen | 7dc60e1 | 2011-01-24 19:46:32 +0000 | [diff] [blame] | 363 | break; | 
| Johnny Chen | 3c75c76 | 2011-01-22 00:47:08 +0000 | [diff] [blame] | 364 | case eEncodingA1: | 
| Johnny Chen | 108d5aa | 2011-01-26 01:00:55 +0000 | [diff] [blame] | 365 | registers = Bits32(opcode, 15, 0); | 
| Johnny Chen | a33d484 | 2011-01-24 22:25:48 +0000 | [diff] [blame] | 366 | // Instead of return false, let's handle the following case as well, | 
|  | 367 | // which amounts to pushing one reg onto the full descending stacks. | 
|  | 368 | // if BitCount(register_list) < 2 then SEE STMDB / STMFD; | 
| Johnny Chen | 3c75c76 | 2011-01-22 00:47:08 +0000 | [diff] [blame] | 369 | break; | 
|  | 370 | case eEncodingA2: | 
| Johnny Chen | 108d5aa | 2011-01-26 01:00:55 +0000 | [diff] [blame] | 371 | Rt = Bits32(opcode, 15, 12); | 
| Johnny Chen | 7dc60e1 | 2011-01-24 19:46:32 +0000 | [diff] [blame] | 372 | // if t == 13 then UNPREDICTABLE; | 
| Johnny Chen | 91d9986 | 2011-01-25 19:07:04 +0000 | [diff] [blame] | 373 | if (Rt == dwarf_sp) | 
| Johnny Chen | 3c75c76 | 2011-01-22 00:47:08 +0000 | [diff] [blame] | 374 | return false; | 
| Johnny Chen | 91d9986 | 2011-01-25 19:07:04 +0000 | [diff] [blame] | 375 | registers = (1u << Rt); | 
| Johnny Chen | 3c75c76 | 2011-01-22 00:47:08 +0000 | [diff] [blame] | 376 | break; | 
| Johnny Chen | ce1ca77 | 2011-01-25 01:13:00 +0000 | [diff] [blame] | 377 | default: | 
|  | 378 | return false; | 
| Johnny Chen | 3c75c76 | 2011-01-22 00:47:08 +0000 | [diff] [blame] | 379 | } | 
| Johnny Chen | ce1ca77 | 2011-01-25 01:13:00 +0000 | [diff] [blame] | 380 | addr_t sp_offset = addr_byte_size * BitCount (registers); | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 381 | addr_t addr = sp - sp_offset; | 
|  | 382 | uint32_t i; | 
|  | 383 |  | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 384 | EmulateInstruction::Context context; | 
| Greg Clayton | 107e53d | 2011-07-06 04:07:21 +0000 | [diff] [blame] | 385 | if (conditional) | 
|  | 386 | context.type = EmulateInstruction::eContextRegisterStore; | 
|  | 387 | else | 
|  | 388 | context.type = EmulateInstruction::eContextPushRegisterOnStack; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 389 | RegisterInfo reg_info; | 
|  | 390 | RegisterInfo sp_reg; | 
|  | 391 | GetRegisterInfo (eRegisterKindDWARF, dwarf_sp, sp_reg); | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 392 | for (i=0; i<15; ++i) | 
|  | 393 | { | 
| Johnny Chen | 7c1bf92 | 2011-02-08 23:49:37 +0000 | [diff] [blame] | 394 | if (BitIsSet (registers, i)) | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 395 | { | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 396 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + i, reg_info); | 
|  | 397 | context.SetRegisterToRegisterPlusOffset (reg_info, sp_reg, addr - sp); | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 398 | uint32_t reg_value = ReadCoreReg(i, &success); | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 399 | if (!success) | 
|  | 400 | return false; | 
| Caroline Tice | cc96eb5 | 2011-02-17 19:20:40 +0000 | [diff] [blame] | 401 | if (!MemAWrite (context, addr, reg_value, addr_byte_size)) | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 402 | return false; | 
|  | 403 | addr += addr_byte_size; | 
|  | 404 | } | 
|  | 405 | } | 
|  | 406 |  | 
| Johnny Chen | 7c1bf92 | 2011-02-08 23:49:37 +0000 | [diff] [blame] | 407 | if (BitIsSet (registers, 15)) | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 408 | { | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 409 | GetRegisterInfo (eRegisterKindDWARF, dwarf_pc, reg_info); | 
|  | 410 | context.SetRegisterPlusOffset (reg_info, addr - sp); | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 411 | const uint32_t pc = ReadCoreReg(PC_REG, &success); | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 412 | if (!success) | 
|  | 413 | return false; | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 414 | if (!MemAWrite (context, addr, pc, addr_byte_size)) | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 415 | return false; | 
|  | 416 | } | 
|  | 417 |  | 
|  | 418 | context.type = EmulateInstruction::eContextAdjustStackPointer; | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 419 | context.SetImmediateSigned (-sp_offset); | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 420 |  | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 421 | if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp - sp_offset)) | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 422 | return false; | 
|  | 423 | } | 
|  | 424 | return true; | 
|  | 425 | } | 
|  | 426 |  | 
| Johnny Chen | ef85e91 | 2011-01-31 23:07:40 +0000 | [diff] [blame] | 427 | // Pop Multiple Registers loads multiple registers from the stack, loading from | 
|  | 428 | // consecutive memory locations staring at the address in SP, and updates | 
|  | 429 | // SP to point just above the loaded data. | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 430 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 431 | EmulateInstructionARM::EmulatePOP (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | ef85e91 | 2011-01-31 23:07:40 +0000 | [diff] [blame] | 432 | { | 
|  | 433 | #if 0 | 
|  | 434 | // ARM pseudo code... | 
|  | 435 | if (ConditionPassed()) | 
|  | 436 | { | 
|  | 437 | EncodingSpecificOperations(); NullCheckIfThumbEE(13); | 
|  | 438 | address = SP; | 
|  | 439 | for i = 0 to 14 | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 440 | if registers<i> == '1' then | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 441 | R[i] = if UnalignedAllowed then MemU[address,4] else MemA[address,4]; address = address + 4; | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 442 | if registers<15> == '1' then | 
| Johnny Chen | ef85e91 | 2011-01-31 23:07:40 +0000 | [diff] [blame] | 443 | if UnalignedAllowed then | 
|  | 444 | LoadWritePC(MemU[address,4]); | 
|  | 445 | else | 
|  | 446 | LoadWritePC(MemA[address,4]); | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 447 | if registers<13> == '0' then SP = SP + 4*BitCount(registers); | 
|  | 448 | if registers<13> == '1' then SP = bits(32) UNKNOWN; | 
| Johnny Chen | ef85e91 | 2011-01-31 23:07:40 +0000 | [diff] [blame] | 449 | } | 
|  | 450 | #endif | 
|  | 451 |  | 
|  | 452 | bool success = false; | 
| Johnny Chen | ef85e91 | 2011-01-31 23:07:40 +0000 | [diff] [blame] | 453 |  | 
| Greg Clayton | 107e53d | 2011-07-06 04:07:21 +0000 | [diff] [blame] | 454 | bool conditional = false; | 
|  | 455 | if (ConditionPassed(opcode, &conditional)) | 
|  | 456 | { | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 457 | const uint32_t addr_byte_size = GetAddressByteSize(); | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 458 | const addr_t sp = ReadCoreReg (SP_REG, &success); | 
| Johnny Chen | ef85e91 | 2011-01-31 23:07:40 +0000 | [diff] [blame] | 459 | if (!success) | 
|  | 460 | return false; | 
|  | 461 | uint32_t registers = 0; | 
|  | 462 | uint32_t Rt; // the destination register | 
|  | 463 | switch (encoding) { | 
|  | 464 | case eEncodingT1: | 
|  | 465 | registers = Bits32(opcode, 7, 0); | 
|  | 466 | // The P bit represents PC. | 
| Johnny Chen | bd59990 | 2011-02-10 21:39:01 +0000 | [diff] [blame] | 467 | if (Bit32(opcode, 8)) | 
| Johnny Chen | ef85e91 | 2011-01-31 23:07:40 +0000 | [diff] [blame] | 468 | registers |= (1u << 15); | 
|  | 469 | // if BitCount(registers) < 1 then UNPREDICTABLE; | 
|  | 470 | if (BitCount(registers) < 1) | 
|  | 471 | return false; | 
|  | 472 | break; | 
|  | 473 | case eEncodingT2: | 
|  | 474 | // Ignore bit 13. | 
|  | 475 | registers = Bits32(opcode, 15, 0) & ~0x2000; | 
|  | 476 | // if BitCount(registers) < 2 || (P == '1' && M == '1') then UNPREDICTABLE; | 
| Johnny Chen | bd59990 | 2011-02-10 21:39:01 +0000 | [diff] [blame] | 477 | if (BitCount(registers) < 2 || (Bit32(opcode, 15) && Bit32(opcode, 14))) | 
| Johnny Chen | ef85e91 | 2011-01-31 23:07:40 +0000 | [diff] [blame] | 478 | return false; | 
| Johnny Chen | 098ae2d | 2011-02-12 00:50:05 +0000 | [diff] [blame] | 479 | // if registers<15> == '1' && InITBlock() && !LastInITBlock() then UNPREDICTABLE; | 
|  | 480 | if (BitIsSet(registers, 15) && InITBlock() && !LastInITBlock()) | 
|  | 481 | return false; | 
| Johnny Chen | ef85e91 | 2011-01-31 23:07:40 +0000 | [diff] [blame] | 482 | break; | 
|  | 483 | case eEncodingT3: | 
|  | 484 | Rt = Bits32(opcode, 15, 12); | 
|  | 485 | // if t == 13 || (t == 15 && InITBlock() && !LastInITBlock()) then UNPREDICTABLE; | 
| Johnny Chen | 098ae2d | 2011-02-12 00:50:05 +0000 | [diff] [blame] | 486 | if (Rt == 13) | 
|  | 487 | return false; | 
|  | 488 | if (Rt == 15 && InITBlock() && !LastInITBlock()) | 
| Johnny Chen | ef85e91 | 2011-01-31 23:07:40 +0000 | [diff] [blame] | 489 | return false; | 
|  | 490 | registers = (1u << Rt); | 
|  | 491 | break; | 
|  | 492 | case eEncodingA1: | 
|  | 493 | registers = Bits32(opcode, 15, 0); | 
|  | 494 | // Instead of return false, let's handle the following case as well, | 
|  | 495 | // which amounts to popping one reg from the full descending stacks. | 
|  | 496 | // if BitCount(register_list) < 2 then SEE LDM / LDMIA / LDMFD; | 
|  | 497 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 498 | // if registers<13> == '1' && ArchVersion() >= 7 then UNPREDICTABLE; | 
| Johnny Chen | 098ae2d | 2011-02-12 00:50:05 +0000 | [diff] [blame] | 499 | if (BitIsSet(opcode, 13) && ArchVersion() >= ARMv7) | 
| Johnny Chen | ef85e91 | 2011-01-31 23:07:40 +0000 | [diff] [blame] | 500 | return false; | 
|  | 501 | break; | 
|  | 502 | case eEncodingA2: | 
|  | 503 | Rt = Bits32(opcode, 15, 12); | 
|  | 504 | // if t == 13 then UNPREDICTABLE; | 
|  | 505 | if (Rt == dwarf_sp) | 
|  | 506 | return false; | 
|  | 507 | registers = (1u << Rt); | 
|  | 508 | break; | 
|  | 509 | default: | 
|  | 510 | return false; | 
|  | 511 | } | 
|  | 512 | addr_t sp_offset = addr_byte_size * BitCount (registers); | 
|  | 513 | addr_t addr = sp; | 
|  | 514 | uint32_t i, data; | 
|  | 515 |  | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 516 | EmulateInstruction::Context context; | 
| Greg Clayton | 107e53d | 2011-07-06 04:07:21 +0000 | [diff] [blame] | 517 | if (conditional) | 
|  | 518 | context.type = EmulateInstruction::eContextRegisterLoad; | 
|  | 519 | else | 
|  | 520 | context.type = EmulateInstruction::eContextPopRegisterOffStack; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 521 |  | 
|  | 522 | RegisterInfo sp_reg; | 
|  | 523 | GetRegisterInfo (eRegisterKindDWARF, dwarf_sp, sp_reg); | 
|  | 524 |  | 
| Johnny Chen | ef85e91 | 2011-01-31 23:07:40 +0000 | [diff] [blame] | 525 | for (i=0; i<15; ++i) | 
|  | 526 | { | 
| Johnny Chen | 7c1bf92 | 2011-02-08 23:49:37 +0000 | [diff] [blame] | 527 | if (BitIsSet (registers, i)) | 
| Johnny Chen | ef85e91 | 2011-01-31 23:07:40 +0000 | [diff] [blame] | 528 | { | 
| Caroline Tice | 8ce836d | 2011-03-16 22:46:55 +0000 | [diff] [blame] | 529 | context.SetRegisterPlusOffset (sp_reg, addr - sp); | 
| Caroline Tice | cc96eb5 | 2011-02-17 19:20:40 +0000 | [diff] [blame] | 530 | data = MemARead(context, addr, 4, 0, &success); | 
| Johnny Chen | ef85e91 | 2011-01-31 23:07:40 +0000 | [diff] [blame] | 531 | if (!success) | 
|  | 532 | return false; | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 533 | if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + i, data)) | 
| Johnny Chen | ef85e91 | 2011-01-31 23:07:40 +0000 | [diff] [blame] | 534 | return false; | 
|  | 535 | addr += addr_byte_size; | 
|  | 536 | } | 
|  | 537 | } | 
|  | 538 |  | 
| Johnny Chen | 7c1bf92 | 2011-02-08 23:49:37 +0000 | [diff] [blame] | 539 | if (BitIsSet (registers, 15)) | 
| Johnny Chen | ef85e91 | 2011-01-31 23:07:40 +0000 | [diff] [blame] | 540 | { | 
| Caroline Tice | 8ce836d | 2011-03-16 22:46:55 +0000 | [diff] [blame] | 541 | context.SetRegisterPlusOffset (sp_reg, addr - sp); | 
| Caroline Tice | cc96eb5 | 2011-02-17 19:20:40 +0000 | [diff] [blame] | 542 | data = MemARead(context, addr, 4, 0, &success); | 
| Johnny Chen | ef85e91 | 2011-01-31 23:07:40 +0000 | [diff] [blame] | 543 | if (!success) | 
|  | 544 | return false; | 
| Johnny Chen | f3eaacf | 2011-02-09 19:30:49 +0000 | [diff] [blame] | 545 | // In ARMv5T and above, this is an interworking branch. | 
| Johnny Chen | 668b451 | 2011-02-15 21:08:58 +0000 | [diff] [blame] | 546 | if (!LoadWritePC(context, data)) | 
| Johnny Chen | ef85e91 | 2011-01-31 23:07:40 +0000 | [diff] [blame] | 547 | return false; | 
|  | 548 | addr += addr_byte_size; | 
|  | 549 | } | 
|  | 550 |  | 
|  | 551 | context.type = EmulateInstruction::eContextAdjustStackPointer; | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 552 | context.SetImmediateSigned (sp_offset); | 
| Johnny Chen | ef85e91 | 2011-01-31 23:07:40 +0000 | [diff] [blame] | 553 |  | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 554 | if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp + sp_offset)) | 
| Johnny Chen | ef85e91 | 2011-01-31 23:07:40 +0000 | [diff] [blame] | 555 | return false; | 
|  | 556 | } | 
|  | 557 | return true; | 
|  | 558 | } | 
|  | 559 |  | 
| Johnny Chen | 5b442b7 | 2011-01-27 19:34:30 +0000 | [diff] [blame] | 560 | // Set r7 or ip to point to saved value residing within the stack. | 
| Johnny Chen | bcec3af | 2011-01-27 01:26:19 +0000 | [diff] [blame] | 561 | // ADD (SP plus immediate) | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 562 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 563 | EmulateInstructionARM::EmulateADDRdSPImm (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | bcec3af | 2011-01-27 01:26:19 +0000 | [diff] [blame] | 564 | { | 
|  | 565 | #if 0 | 
|  | 566 | // ARM pseudo code... | 
|  | 567 | if (ConditionPassed()) | 
|  | 568 | { | 
|  | 569 | EncodingSpecificOperations(); | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 570 | (result, carry, overflow) = AddWithCarry(SP, imm32, '0'); | 
| Johnny Chen | bcec3af | 2011-01-27 01:26:19 +0000 | [diff] [blame] | 571 | if d == 15 then | 
|  | 572 | ALUWritePC(result); // setflags is always FALSE here | 
|  | 573 | else | 
|  | 574 | R[d] = result; | 
|  | 575 | if setflags then | 
|  | 576 | APSR.N = result<31>; | 
|  | 577 | APSR.Z = IsZeroBit(result); | 
|  | 578 | APSR.C = carry; | 
|  | 579 | APSR.V = overflow; | 
|  | 580 | } | 
|  | 581 | #endif | 
|  | 582 |  | 
|  | 583 | bool success = false; | 
| Johnny Chen | bcec3af | 2011-01-27 01:26:19 +0000 | [diff] [blame] | 584 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 585 | if (ConditionPassed(opcode)) | 
| Johnny Chen | bcec3af | 2011-01-27 01:26:19 +0000 | [diff] [blame] | 586 | { | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 587 | const addr_t sp = ReadCoreReg (SP_REG, &success); | 
| Johnny Chen | bcec3af | 2011-01-27 01:26:19 +0000 | [diff] [blame] | 588 | if (!success) | 
|  | 589 | return false; | 
|  | 590 | uint32_t Rd; // the destination register | 
|  | 591 | uint32_t imm32; | 
|  | 592 | switch (encoding) { | 
|  | 593 | case eEncodingT1: | 
|  | 594 | Rd = 7; | 
|  | 595 | imm32 = Bits32(opcode, 7, 0) << 2; // imm32 = ZeroExtend(imm8:'00', 32) | 
|  | 596 | break; | 
|  | 597 | case eEncodingA1: | 
|  | 598 | Rd = Bits32(opcode, 15, 12); | 
|  | 599 | imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12) | 
|  | 600 | break; | 
|  | 601 | default: | 
|  | 602 | return false; | 
|  | 603 | } | 
|  | 604 | addr_t sp_offset = imm32; | 
|  | 605 | addr_t addr = sp + sp_offset; // a pointer to the stack area | 
|  | 606 |  | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 607 | EmulateInstruction::Context context; | 
| Greg Clayton | 75906e4 | 2011-05-11 18:39:18 +0000 | [diff] [blame] | 608 | context.type = eContextSetFramePointer; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 609 | RegisterInfo sp_reg; | 
|  | 610 | GetRegisterInfo (eRegisterKindDWARF, dwarf_sp, sp_reg); | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 611 | context.SetRegisterPlusOffset (sp_reg, sp_offset); | 
| Johnny Chen | bcec3af | 2011-01-27 01:26:19 +0000 | [diff] [blame] | 612 |  | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 613 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rd, addr)) | 
| Johnny Chen | bcec3af | 2011-01-27 01:26:19 +0000 | [diff] [blame] | 614 | return false; | 
|  | 615 | } | 
|  | 616 | return true; | 
|  | 617 | } | 
|  | 618 |  | 
| Johnny Chen | 2ccad83 | 2011-01-28 19:57:25 +0000 | [diff] [blame] | 619 | // Set r7 or ip to the current stack pointer. | 
|  | 620 | // MOV (register) | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 621 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 622 | EmulateInstructionARM::EmulateMOVRdSP (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | 2ccad83 | 2011-01-28 19:57:25 +0000 | [diff] [blame] | 623 | { | 
|  | 624 | #if 0 | 
|  | 625 | // ARM pseudo code... | 
|  | 626 | if (ConditionPassed()) | 
|  | 627 | { | 
|  | 628 | EncodingSpecificOperations(); | 
|  | 629 | result = R[m]; | 
|  | 630 | if d == 15 then | 
|  | 631 | ALUWritePC(result); // setflags is always FALSE here | 
|  | 632 | else | 
|  | 633 | R[d] = result; | 
|  | 634 | if setflags then | 
|  | 635 | APSR.N = result<31>; | 
|  | 636 | APSR.Z = IsZeroBit(result); | 
|  | 637 | // APSR.C unchanged | 
|  | 638 | // APSR.V unchanged | 
|  | 639 | } | 
|  | 640 | #endif | 
|  | 641 |  | 
|  | 642 | bool success = false; | 
| Johnny Chen | 2ccad83 | 2011-01-28 19:57:25 +0000 | [diff] [blame] | 643 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 644 | if (ConditionPassed(opcode)) | 
| Johnny Chen | 2ccad83 | 2011-01-28 19:57:25 +0000 | [diff] [blame] | 645 | { | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 646 | const addr_t sp = ReadCoreReg (SP_REG, &success); | 
| Johnny Chen | 2ccad83 | 2011-01-28 19:57:25 +0000 | [diff] [blame] | 647 | if (!success) | 
|  | 648 | return false; | 
|  | 649 | uint32_t Rd; // the destination register | 
|  | 650 | switch (encoding) { | 
|  | 651 | case eEncodingT1: | 
|  | 652 | Rd = 7; | 
|  | 653 | break; | 
|  | 654 | case eEncodingA1: | 
|  | 655 | Rd = 12; | 
|  | 656 | break; | 
|  | 657 | default: | 
|  | 658 | return false; | 
|  | 659 | } | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 660 |  | 
|  | 661 | EmulateInstruction::Context context; | 
| Greg Clayton | 04d397c | 2011-05-23 18:04:09 +0000 | [diff] [blame] | 662 | if (Rd == GetFramePointerRegisterNumber()) | 
|  | 663 | context.type = EmulateInstruction::eContextSetFramePointer; | 
|  | 664 | else | 
|  | 665 | context.type = EmulateInstruction::eContextRegisterPlusOffset; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 666 | RegisterInfo sp_reg; | 
|  | 667 | GetRegisterInfo (eRegisterKindDWARF, dwarf_sp, sp_reg); | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 668 | context.SetRegisterPlusOffset (sp_reg, 0); | 
| Johnny Chen | 2ccad83 | 2011-01-28 19:57:25 +0000 | [diff] [blame] | 669 |  | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 670 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rd, sp)) | 
| Johnny Chen | 2ccad83 | 2011-01-28 19:57:25 +0000 | [diff] [blame] | 671 | return false; | 
|  | 672 | } | 
|  | 673 | return true; | 
|  | 674 | } | 
|  | 675 |  | 
| Johnny Chen | 1c13b62 | 2011-01-29 00:11:15 +0000 | [diff] [blame] | 676 | // Move from high register (r8-r15) to low register (r0-r7). | 
|  | 677 | // MOV (register) | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 678 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 679 | EmulateInstructionARM::EmulateMOVLowHigh (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | 1c13b62 | 2011-01-29 00:11:15 +0000 | [diff] [blame] | 680 | { | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 681 | return EmulateMOVRdRm (opcode, encoding); | 
| Johnny Chen | 338bf54 | 2011-02-10 19:29:03 +0000 | [diff] [blame] | 682 | } | 
|  | 683 |  | 
|  | 684 | // Move from register to register. | 
|  | 685 | // MOV (register) | 
|  | 686 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 687 | EmulateInstructionARM::EmulateMOVRdRm (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | 338bf54 | 2011-02-10 19:29:03 +0000 | [diff] [blame] | 688 | { | 
| Johnny Chen | 1c13b62 | 2011-01-29 00:11:15 +0000 | [diff] [blame] | 689 | #if 0 | 
|  | 690 | // ARM pseudo code... | 
|  | 691 | if (ConditionPassed()) | 
|  | 692 | { | 
|  | 693 | EncodingSpecificOperations(); | 
|  | 694 | result = R[m]; | 
|  | 695 | if d == 15 then | 
|  | 696 | ALUWritePC(result); // setflags is always FALSE here | 
|  | 697 | else | 
|  | 698 | R[d] = result; | 
|  | 699 | if setflags then | 
|  | 700 | APSR.N = result<31>; | 
|  | 701 | APSR.Z = IsZeroBit(result); | 
|  | 702 | // APSR.C unchanged | 
|  | 703 | // APSR.V unchanged | 
|  | 704 | } | 
|  | 705 | #endif | 
|  | 706 |  | 
|  | 707 | bool success = false; | 
| Johnny Chen | 1c13b62 | 2011-01-29 00:11:15 +0000 | [diff] [blame] | 708 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 709 | if (ConditionPassed(opcode)) | 
| Johnny Chen | 1c13b62 | 2011-01-29 00:11:15 +0000 | [diff] [blame] | 710 | { | 
|  | 711 | uint32_t Rm; // the source register | 
|  | 712 | uint32_t Rd; // the destination register | 
| Johnny Chen | 338bf54 | 2011-02-10 19:29:03 +0000 | [diff] [blame] | 713 | bool setflags; | 
| Johnny Chen | 1c13b62 | 2011-01-29 00:11:15 +0000 | [diff] [blame] | 714 | switch (encoding) { | 
|  | 715 | case eEncodingT1: | 
| Johnny Chen | 7c5234d | 2011-02-18 23:41:11 +0000 | [diff] [blame] | 716 | Rd = Bit32(opcode, 7) << 3 | Bits32(opcode, 2, 0); | 
| Johnny Chen | 1c13b62 | 2011-01-29 00:11:15 +0000 | [diff] [blame] | 717 | Rm = Bits32(opcode, 6, 3); | 
| Johnny Chen | 338bf54 | 2011-02-10 19:29:03 +0000 | [diff] [blame] | 718 | setflags = false; | 
| Johnny Chen | 7c5234d | 2011-02-18 23:41:11 +0000 | [diff] [blame] | 719 | if (Rd == 15 && InITBlock() && !LastInITBlock()) | 
|  | 720 | return false; | 
| Johnny Chen | 338bf54 | 2011-02-10 19:29:03 +0000 | [diff] [blame] | 721 | break; | 
|  | 722 | case eEncodingT2: | 
| Johnny Chen | 7c5234d | 2011-02-18 23:41:11 +0000 | [diff] [blame] | 723 | Rd = Bits32(opcode, 2, 0); | 
| Johnny Chen | 338bf54 | 2011-02-10 19:29:03 +0000 | [diff] [blame] | 724 | Rm = Bits32(opcode, 5, 3); | 
| Johnny Chen | 338bf54 | 2011-02-10 19:29:03 +0000 | [diff] [blame] | 725 | setflags = true; | 
| Johnny Chen | 7c5234d | 2011-02-18 23:41:11 +0000 | [diff] [blame] | 726 | if (InITBlock()) | 
|  | 727 | return false; | 
| Johnny Chen | 1c13b62 | 2011-01-29 00:11:15 +0000 | [diff] [blame] | 728 | break; | 
| Johnny Chen | 7c5234d | 2011-02-18 23:41:11 +0000 | [diff] [blame] | 729 | case eEncodingT3: | 
|  | 730 | Rd = Bits32(opcode, 11, 8); | 
|  | 731 | Rm = Bits32(opcode, 3, 0); | 
|  | 732 | setflags = BitIsSet(opcode, 20); | 
|  | 733 | // if setflags && (BadReg(d) || BadReg(m)) then UNPREDICTABLE; | 
|  | 734 | if (setflags && (BadReg(Rd) || BadReg(Rm))) | 
|  | 735 | return false; | 
|  | 736 | // if !setflags && (d == 15 || m == 15 || (d == 13 && m == 13)) then UNPREDICTABLE; | 
|  | 737 | if (!setflags && (Rd == 15 || Rm == 15 || (Rd == 13 && Rm == 13))) | 
|  | 738 | return false; | 
| Johnny Chen | ed32e7c | 2011-02-22 23:42:58 +0000 | [diff] [blame] | 739 | break; | 
| Johnny Chen | 01d6157 | 2011-02-25 00:23:25 +0000 | [diff] [blame] | 740 | case eEncodingA1: | 
|  | 741 | Rd = Bits32(opcode, 15, 12); | 
|  | 742 | Rm = Bits32(opcode, 3, 0); | 
|  | 743 | setflags = BitIsSet(opcode, 20); | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 744 |  | 
| Johnny Chen | 01d6157 | 2011-02-25 00:23:25 +0000 | [diff] [blame] | 745 | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related instructions; | 
| Johnny Chen | 01d6157 | 2011-02-25 00:23:25 +0000 | [diff] [blame] | 746 | if (Rd == 15 && setflags) | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 747 | return EmulateSUBSPcLrEtc (opcode, encoding); | 
| Johnny Chen | 01d6157 | 2011-02-25 00:23:25 +0000 | [diff] [blame] | 748 | break; | 
| Johnny Chen | 1c13b62 | 2011-01-29 00:11:15 +0000 | [diff] [blame] | 749 | default: | 
|  | 750 | return false; | 
|  | 751 | } | 
| Johnny Chen | 7c5234d | 2011-02-18 23:41:11 +0000 | [diff] [blame] | 752 | uint32_t result = ReadCoreReg(Rm, &success); | 
| Johnny Chen | 1c13b62 | 2011-01-29 00:11:15 +0000 | [diff] [blame] | 753 | if (!success) | 
|  | 754 | return false; | 
|  | 755 |  | 
|  | 756 | // The context specifies that Rm is to be moved into Rd. | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 757 | EmulateInstruction::Context context; | 
| Caroline Tice | 2b03ed8 | 2011-03-16 00:06:12 +0000 | [diff] [blame] | 758 | context.type = EmulateInstruction::eContextRegisterLoad; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 759 | RegisterInfo dwarf_reg; | 
|  | 760 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + Rm, dwarf_reg); | 
| Caroline Tice | 2b03ed8 | 2011-03-16 00:06:12 +0000 | [diff] [blame] | 761 | context.SetRegister (dwarf_reg); | 
| Johnny Chen | ca67d1c | 2011-02-17 01:35:27 +0000 | [diff] [blame] | 762 |  | 
| Johnny Chen | 10530c2 | 2011-02-17 22:37:12 +0000 | [diff] [blame] | 763 | if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags)) | 
| Johnny Chen | ca67d1c | 2011-02-17 01:35:27 +0000 | [diff] [blame] | 764 | return false; | 
| Johnny Chen | 1c13b62 | 2011-01-29 00:11:15 +0000 | [diff] [blame] | 765 | } | 
|  | 766 | return true; | 
|  | 767 | } | 
|  | 768 |  | 
| Johnny Chen | 357c30f | 2011-02-14 22:04:25 +0000 | [diff] [blame] | 769 | // Move (immediate) writes an immediate value to the destination register.  It | 
|  | 770 | // can optionally update the condition flags based on the value. | 
|  | 771 | // MOV (immediate) | 
|  | 772 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 773 | EmulateInstructionARM::EmulateMOVRdImm (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | 357c30f | 2011-02-14 22:04:25 +0000 | [diff] [blame] | 774 | { | 
|  | 775 | #if 0 | 
|  | 776 | // ARM pseudo code... | 
|  | 777 | if (ConditionPassed()) | 
|  | 778 | { | 
|  | 779 | EncodingSpecificOperations(); | 
|  | 780 | result = imm32; | 
|  | 781 | if d == 15 then         // Can only occur for ARM encoding | 
|  | 782 | ALUWritePC(result); // setflags is always FALSE here | 
|  | 783 | else | 
|  | 784 | R[d] = result; | 
|  | 785 | if setflags then | 
|  | 786 | APSR.N = result<31>; | 
|  | 787 | APSR.Z = IsZeroBit(result); | 
|  | 788 | APSR.C = carry; | 
|  | 789 | // APSR.V unchanged | 
|  | 790 | } | 
|  | 791 | #endif | 
| Johnny Chen | 357c30f | 2011-02-14 22:04:25 +0000 | [diff] [blame] | 792 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 793 | if (ConditionPassed(opcode)) | 
| Johnny Chen | 357c30f | 2011-02-14 22:04:25 +0000 | [diff] [blame] | 794 | { | 
|  | 795 | uint32_t Rd; // the destination register | 
| Johnny Chen | 357c30f | 2011-02-14 22:04:25 +0000 | [diff] [blame] | 796 | uint32_t imm32; // the immediate value to be written to Rd | 
| Johnny Chen | 65f39ed | 2011-08-12 01:10:45 +0000 | [diff] [blame] | 797 | uint32_t carry = 0; // the carry bit after ThumbExpandImm_C or ARMExpandImm_C. | 
|  | 798 | // for setflags == false, this value is a don't care | 
|  | 799 | // initialized to 0 to silence the static analyzer | 
| Johnny Chen | 357c30f | 2011-02-14 22:04:25 +0000 | [diff] [blame] | 800 | bool setflags; | 
|  | 801 | switch (encoding) { | 
| Caroline Tice | 89c6d58 | 2011-03-29 19:53:44 +0000 | [diff] [blame] | 802 | case eEncodingT1: | 
|  | 803 | Rd = Bits32(opcode, 10, 8); | 
|  | 804 | setflags = !InITBlock(); | 
|  | 805 | imm32 = Bits32(opcode, 7, 0); // imm32 = ZeroExtend(imm8, 32) | 
|  | 806 | carry = APSR_C; | 
|  | 807 |  | 
|  | 808 | break; | 
|  | 809 |  | 
|  | 810 | case eEncodingT2: | 
|  | 811 | Rd = Bits32(opcode, 11, 8); | 
|  | 812 | setflags = BitIsSet(opcode, 20); | 
|  | 813 | imm32 = ThumbExpandImm_C(opcode, APSR_C, carry); | 
|  | 814 | if (BadReg(Rd)) | 
|  | 815 | return false; | 
|  | 816 |  | 
|  | 817 | break; | 
|  | 818 |  | 
|  | 819 | case eEncodingT3: | 
|  | 820 | { | 
|  | 821 | // d = UInt(Rd); setflags = FALSE; imm32 = ZeroExtend(imm4:i:imm3:imm8, 32); | 
|  | 822 | Rd = Bits32 (opcode, 11, 8); | 
|  | 823 | setflags = false; | 
|  | 824 | uint32_t imm4 = Bits32 (opcode, 19, 16); | 
|  | 825 | uint32_t imm3 = Bits32 (opcode, 14, 12); | 
|  | 826 | uint32_t i = Bit32 (opcode, 26); | 
|  | 827 | uint32_t imm8 = Bits32 (opcode, 7, 0); | 
|  | 828 | imm32 = (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8; | 
|  | 829 |  | 
|  | 830 | // if BadReg(d) then UNPREDICTABLE; | 
|  | 831 | if (BadReg (Rd)) | 
|  | 832 | return false; | 
|  | 833 | } | 
|  | 834 | break; | 
|  | 835 |  | 
|  | 836 | case eEncodingA1: | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 837 | // d = UInt(Rd); setflags = (S == Ô1Õ); (imm32, carry) = ARMExpandImm_C(imm12, APSR.C); | 
| Caroline Tice | 89c6d58 | 2011-03-29 19:53:44 +0000 | [diff] [blame] | 838 | Rd = Bits32 (opcode, 15, 12); | 
|  | 839 | setflags = BitIsSet (opcode, 20); | 
|  | 840 | imm32 = ARMExpandImm_C (opcode, APSR_C, carry); | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 841 |  | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 842 | // if Rd == Ô1111Õ && S == Ô1Õ then SEE SUBS PC, LR and related instructions; | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 843 | if ((Rd == 15) && setflags) | 
|  | 844 | return EmulateSUBSPcLrEtc (opcode, encoding); | 
| Caroline Tice | 89c6d58 | 2011-03-29 19:53:44 +0000 | [diff] [blame] | 845 |  | 
|  | 846 | break; | 
|  | 847 |  | 
|  | 848 | case eEncodingA2: | 
|  | 849 | { | 
|  | 850 | // d = UInt(Rd); setflags = FALSE; imm32 = ZeroExtend(imm4:imm12, 32); | 
|  | 851 | Rd = Bits32 (opcode, 15, 12); | 
|  | 852 | setflags = false; | 
|  | 853 | uint32_t imm4 = Bits32 (opcode, 19, 16); | 
|  | 854 | uint32_t imm12 = Bits32 (opcode, 11, 0); | 
|  | 855 | imm32 = (imm4 << 12) | imm12; | 
|  | 856 |  | 
|  | 857 | // if d == 15 then UNPREDICTABLE; | 
|  | 858 | if (Rd == 15) | 
|  | 859 | return false; | 
|  | 860 | } | 
|  | 861 | break; | 
|  | 862 |  | 
|  | 863 | default: | 
| Johnny Chen | 9798cfc | 2011-02-14 23:33:58 +0000 | [diff] [blame] | 864 | return false; | 
| Johnny Chen | 357c30f | 2011-02-14 22:04:25 +0000 | [diff] [blame] | 865 | } | 
|  | 866 | uint32_t result = imm32; | 
|  | 867 |  | 
|  | 868 | // The context specifies that an immediate is to be moved into Rd. | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 869 | EmulateInstruction::Context context; | 
|  | 870 | context.type = EmulateInstruction::eContextImmediate; | 
|  | 871 | context.SetNoArgs (); | 
| Johnny Chen | ca67d1c | 2011-02-17 01:35:27 +0000 | [diff] [blame] | 872 |  | 
| Johnny Chen | 10530c2 | 2011-02-17 22:37:12 +0000 | [diff] [blame] | 873 | if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry)) | 
| Johnny Chen | ca67d1c | 2011-02-17 01:35:27 +0000 | [diff] [blame] | 874 | return false; | 
| Johnny Chen | 357c30f | 2011-02-14 22:04:25 +0000 | [diff] [blame] | 875 | } | 
|  | 876 | return true; | 
|  | 877 | } | 
|  | 878 |  | 
| Caroline Tice | 5c1e2ed | 2011-03-02 22:43:54 +0000 | [diff] [blame] | 879 | // MUL multiplies two register values.  The least significant 32 bits of the result are written to the destination | 
|  | 880 | // register.  These 32 bits do not depend on whether the source register values are considered to be signed values or | 
|  | 881 | // unsigned values. | 
|  | 882 | // | 
|  | 883 | // Optionally, it can update the condition flags based on the result.  In the Thumb instruction set, this option is | 
|  | 884 | // limited to only a few forms of the instruction. | 
|  | 885 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 886 | EmulateInstructionARM::EmulateMUL (const uint32_t opcode, const ARMEncoding encoding) | 
| Caroline Tice | 5c1e2ed | 2011-03-02 22:43:54 +0000 | [diff] [blame] | 887 | { | 
|  | 888 | #if 0 | 
|  | 889 | if ConditionPassed() then | 
|  | 890 | EncodingSpecificOperations(); | 
|  | 891 | operand1 = SInt(R[n]); // operand1 = UInt(R[n]) produces the same final results | 
|  | 892 | operand2 = SInt(R[m]); // operand2 = UInt(R[m]) produces the same final results | 
|  | 893 | result = operand1 * operand2; | 
|  | 894 | R[d] = result<31:0>; | 
|  | 895 | if setflags then | 
|  | 896 | APSR.N = result<31>; | 
|  | 897 | APSR.Z = IsZeroBit(result); | 
|  | 898 | if ArchVersion() == 4 then | 
|  | 899 | APSR.C = bit UNKNOWN; | 
|  | 900 | // else APSR.C unchanged | 
|  | 901 | // APSR.V always unchanged | 
|  | 902 | #endif | 
| Caroline Tice | 5c1e2ed | 2011-03-02 22:43:54 +0000 | [diff] [blame] | 903 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 904 | if (ConditionPassed(opcode)) | 
| Caroline Tice | 5c1e2ed | 2011-03-02 22:43:54 +0000 | [diff] [blame] | 905 | { | 
|  | 906 | uint32_t d; | 
|  | 907 | uint32_t n; | 
|  | 908 | uint32_t m; | 
|  | 909 | bool setflags; | 
|  | 910 |  | 
|  | 911 | // EncodingSpecificOperations(); | 
|  | 912 | switch (encoding) | 
|  | 913 | { | 
|  | 914 | case eEncodingT1: | 
|  | 915 | // d = UInt(Rdm); n = UInt(Rn); m = UInt(Rdm); setflags = !InITBlock(); | 
|  | 916 | d = Bits32 (opcode, 2, 0); | 
|  | 917 | n = Bits32 (opcode, 5, 3); | 
|  | 918 | m = Bits32 (opcode, 2, 0); | 
|  | 919 | setflags = !InITBlock(); | 
|  | 920 |  | 
|  | 921 | // if ArchVersion() < 6 && d == n then UNPREDICTABLE; | 
|  | 922 | if ((ArchVersion() < ARMv6) && (d == n)) | 
|  | 923 | return false; | 
|  | 924 |  | 
|  | 925 | break; | 
|  | 926 |  | 
|  | 927 | case eEncodingT2: | 
|  | 928 | // d = UInt(Rd); n = UInt(Rn); m = UInt(Rm); setflags = FALSE; | 
|  | 929 | d = Bits32 (opcode, 11, 8); | 
|  | 930 | n = Bits32 (opcode, 19, 16); | 
|  | 931 | m = Bits32 (opcode, 3, 0); | 
|  | 932 | setflags = false; | 
|  | 933 |  | 
|  | 934 | // if BadReg(d) || BadReg(n) || BadReg(m) then UNPREDICTABLE; | 
|  | 935 | if (BadReg (d) || BadReg (n) || BadReg (m)) | 
|  | 936 | return false; | 
|  | 937 |  | 
|  | 938 | break; | 
|  | 939 |  | 
|  | 940 | case eEncodingA1: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 941 | // d = UInt(Rd); n = UInt(Rn); m = UInt(Rm); setflags = (S == '1'); | 
| Caroline Tice | 5c1e2ed | 2011-03-02 22:43:54 +0000 | [diff] [blame] | 942 | d = Bits32 (opcode, 19, 16); | 
|  | 943 | n = Bits32 (opcode, 3, 0); | 
|  | 944 | m = Bits32 (opcode, 11, 8); | 
|  | 945 | setflags = BitIsSet (opcode, 20); | 
|  | 946 |  | 
|  | 947 | // if d == 15 || n == 15 || m == 15 then UNPREDICTABLE; | 
|  | 948 | if ((d == 15) ||  (n == 15) || (m == 15)) | 
|  | 949 | return false; | 
|  | 950 |  | 
|  | 951 | // if ArchVersion() < 6 && d == n then UNPREDICTABLE; | 
|  | 952 | if ((ArchVersion() < ARMv6) && (d == n)) | 
|  | 953 | return false; | 
|  | 954 |  | 
|  | 955 | break; | 
|  | 956 |  | 
|  | 957 | default: | 
|  | 958 | return false; | 
|  | 959 | } | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 960 |  | 
|  | 961 | bool success = false; | 
|  | 962 |  | 
| Caroline Tice | 5c1e2ed | 2011-03-02 22:43:54 +0000 | [diff] [blame] | 963 | // operand1 = SInt(R[n]); // operand1 = UInt(R[n]) produces the same final results | 
|  | 964 | uint64_t operand1 = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success); | 
|  | 965 | if (!success) | 
|  | 966 | return false; | 
|  | 967 |  | 
|  | 968 | // operand2 = SInt(R[m]); // operand2 = UInt(R[m]) produces the same final results | 
|  | 969 | uint64_t operand2 = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + m, 0, &success); | 
|  | 970 | if (!success) | 
|  | 971 | return false; | 
|  | 972 |  | 
|  | 973 | // result = operand1 * operand2; | 
|  | 974 | uint64_t result = operand1 * operand2; | 
|  | 975 |  | 
|  | 976 | // R[d] = result<31:0>; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 977 | RegisterInfo op1_reg; | 
|  | 978 | RegisterInfo op2_reg; | 
|  | 979 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, op1_reg); | 
|  | 980 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + m, op2_reg); | 
| Caroline Tice | 5c1e2ed | 2011-03-02 22:43:54 +0000 | [diff] [blame] | 981 |  | 
|  | 982 | EmulateInstruction::Context context; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 983 | context.type = eContextArithmetic; | 
| Caroline Tice | 5c1e2ed | 2011-03-02 22:43:54 +0000 | [diff] [blame] | 984 | context.SetRegisterRegisterOperands (op1_reg, op2_reg); | 
|  | 985 |  | 
|  | 986 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + d, (0x0000ffff & result))) | 
|  | 987 | return false; | 
|  | 988 |  | 
|  | 989 | // if setflags then | 
|  | 990 | if (setflags) | 
|  | 991 | { | 
|  | 992 | // APSR.N = result<31>; | 
|  | 993 | // APSR.Z = IsZeroBit(result); | 
| Greg Clayton | b344843 | 2011-03-24 21:19:54 +0000 | [diff] [blame] | 994 | m_new_inst_cpsr = m_opcode_cpsr; | 
| Caroline Tice | 5c1e2ed | 2011-03-02 22:43:54 +0000 | [diff] [blame] | 995 | SetBit32 (m_new_inst_cpsr, CPSR_N_POS, Bit32 (result, 31)); | 
|  | 996 | SetBit32 (m_new_inst_cpsr, CPSR_Z_POS, result == 0 ? 1 : 0); | 
| Greg Clayton | b344843 | 2011-03-24 21:19:54 +0000 | [diff] [blame] | 997 | if (m_new_inst_cpsr != m_opcode_cpsr) | 
| Caroline Tice | 5c1e2ed | 2011-03-02 22:43:54 +0000 | [diff] [blame] | 998 | { | 
|  | 999 | if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS, m_new_inst_cpsr)) | 
|  | 1000 | return false; | 
|  | 1001 | } | 
|  | 1002 |  | 
|  | 1003 | // if ArchVersion() == 4 then | 
|  | 1004 | // APSR.C = bit UNKNOWN; | 
|  | 1005 | } | 
|  | 1006 | } | 
|  | 1007 | return true; | 
|  | 1008 | } | 
|  | 1009 |  | 
| Johnny Chen | d642a6a | 2011-02-22 01:01:03 +0000 | [diff] [blame] | 1010 | // Bitwise NOT (immediate) writes the bitwise inverse of an immediate value to the destination register. | 
|  | 1011 | // It can optionally update the condition flags based on the value. | 
| Johnny Chen | 28070c3 | 2011-02-12 01:27:26 +0000 | [diff] [blame] | 1012 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 1013 | EmulateInstructionARM::EmulateMVNImm (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | 28070c3 | 2011-02-12 01:27:26 +0000 | [diff] [blame] | 1014 | { | 
|  | 1015 | #if 0 | 
|  | 1016 | // ARM pseudo code... | 
|  | 1017 | if (ConditionPassed()) | 
|  | 1018 | { | 
|  | 1019 | EncodingSpecificOperations(); | 
|  | 1020 | result = NOT(imm32); | 
|  | 1021 | if d == 15 then         // Can only occur for ARM encoding | 
|  | 1022 | ALUWritePC(result); // setflags is always FALSE here | 
|  | 1023 | else | 
|  | 1024 | R[d] = result; | 
|  | 1025 | if setflags then | 
|  | 1026 | APSR.N = result<31>; | 
|  | 1027 | APSR.Z = IsZeroBit(result); | 
|  | 1028 | APSR.C = carry; | 
|  | 1029 | // APSR.V unchanged | 
|  | 1030 | } | 
|  | 1031 | #endif | 
| Johnny Chen | 33bf6ab | 2011-02-14 20:39:01 +0000 | [diff] [blame] | 1032 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 1033 | if (ConditionPassed(opcode)) | 
| Johnny Chen | 33bf6ab | 2011-02-14 20:39:01 +0000 | [diff] [blame] | 1034 | { | 
|  | 1035 | uint32_t Rd; // the destination register | 
| Johnny Chen | 357c30f | 2011-02-14 22:04:25 +0000 | [diff] [blame] | 1036 | uint32_t imm32; // the output after ThumbExpandImm_C or ARMExpandImm_C | 
|  | 1037 | uint32_t carry; // the carry bit after ThumbExpandImm_C or ARMExpandImm_C | 
| Johnny Chen | 33bf6ab | 2011-02-14 20:39:01 +0000 | [diff] [blame] | 1038 | bool setflags; | 
|  | 1039 | switch (encoding) { | 
|  | 1040 | case eEncodingT1: | 
|  | 1041 | Rd = Bits32(opcode, 11, 8); | 
| Johnny Chen | 33bf6ab | 2011-02-14 20:39:01 +0000 | [diff] [blame] | 1042 | setflags = BitIsSet(opcode, 20); | 
| Johnny Chen | d642a6a | 2011-02-22 01:01:03 +0000 | [diff] [blame] | 1043 | imm32 = ThumbExpandImm_C(opcode, APSR_C, carry); | 
| Johnny Chen | 33bf6ab | 2011-02-14 20:39:01 +0000 | [diff] [blame] | 1044 | break; | 
|  | 1045 | case eEncodingA1: | 
|  | 1046 | Rd = Bits32(opcode, 15, 12); | 
| Johnny Chen | 33bf6ab | 2011-02-14 20:39:01 +0000 | [diff] [blame] | 1047 | setflags = BitIsSet(opcode, 20); | 
| Johnny Chen | d642a6a | 2011-02-22 01:01:03 +0000 | [diff] [blame] | 1048 | imm32 = ARMExpandImm_C(opcode, APSR_C, carry); | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 1049 |  | 
| Johnny Chen | d642a6a | 2011-02-22 01:01:03 +0000 | [diff] [blame] | 1050 | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related instructions; | 
| Johnny Chen | d642a6a | 2011-02-22 01:01:03 +0000 | [diff] [blame] | 1051 | if (Rd == 15 && setflags) | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 1052 | return EmulateSUBSPcLrEtc (opcode, encoding); | 
| Johnny Chen | 33bf6ab | 2011-02-14 20:39:01 +0000 | [diff] [blame] | 1053 | break; | 
|  | 1054 | default: | 
|  | 1055 | return false; | 
|  | 1056 | } | 
|  | 1057 | uint32_t result = ~imm32; | 
|  | 1058 |  | 
|  | 1059 | // The context specifies that an immediate is to be moved into Rd. | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 1060 | EmulateInstruction::Context context; | 
|  | 1061 | context.type = EmulateInstruction::eContextImmediate; | 
|  | 1062 | context.SetNoArgs (); | 
| Johnny Chen | ca67d1c | 2011-02-17 01:35:27 +0000 | [diff] [blame] | 1063 |  | 
| Johnny Chen | 10530c2 | 2011-02-17 22:37:12 +0000 | [diff] [blame] | 1064 | if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry)) | 
| Johnny Chen | ca67d1c | 2011-02-17 01:35:27 +0000 | [diff] [blame] | 1065 | return false; | 
| Johnny Chen | 33bf6ab | 2011-02-14 20:39:01 +0000 | [diff] [blame] | 1066 | } | 
|  | 1067 | return true; | 
| Johnny Chen | 28070c3 | 2011-02-12 01:27:26 +0000 | [diff] [blame] | 1068 | } | 
|  | 1069 |  | 
| Johnny Chen | d642a6a | 2011-02-22 01:01:03 +0000 | [diff] [blame] | 1070 | // Bitwise NOT (register) writes the bitwise inverse of a register value to the destination register. | 
|  | 1071 | // It can optionally update the condition flags based on the result. | 
|  | 1072 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 1073 | EmulateInstructionARM::EmulateMVNReg (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | d642a6a | 2011-02-22 01:01:03 +0000 | [diff] [blame] | 1074 | { | 
|  | 1075 | #if 0 | 
|  | 1076 | // ARM pseudo code... | 
|  | 1077 | if (ConditionPassed()) | 
|  | 1078 | { | 
|  | 1079 | EncodingSpecificOperations(); | 
|  | 1080 | (shifted, carry) = Shift_C(R[m], shift_t, shift_n, APSR.C); | 
|  | 1081 | result = NOT(shifted); | 
|  | 1082 | if d == 15 then         // Can only occur for ARM encoding | 
|  | 1083 | ALUWritePC(result); // setflags is always FALSE here | 
|  | 1084 | else | 
|  | 1085 | R[d] = result; | 
|  | 1086 | if setflags then | 
|  | 1087 | APSR.N = result<31>; | 
|  | 1088 | APSR.Z = IsZeroBit(result); | 
|  | 1089 | APSR.C = carry; | 
|  | 1090 | // APSR.V unchanged | 
|  | 1091 | } | 
|  | 1092 | #endif | 
|  | 1093 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 1094 | if (ConditionPassed(opcode)) | 
| Johnny Chen | d642a6a | 2011-02-22 01:01:03 +0000 | [diff] [blame] | 1095 | { | 
|  | 1096 | uint32_t Rm; // the source register | 
|  | 1097 | uint32_t Rd; // the destination register | 
|  | 1098 | ARM_ShifterType shift_t; | 
|  | 1099 | uint32_t shift_n; // the shift applied to the value read from Rm | 
|  | 1100 | bool setflags; | 
|  | 1101 | uint32_t carry; // the carry bit after the shift operation | 
|  | 1102 | switch (encoding) { | 
|  | 1103 | case eEncodingT1: | 
|  | 1104 | Rd = Bits32(opcode, 2, 0); | 
|  | 1105 | Rm = Bits32(opcode, 5, 3); | 
|  | 1106 | setflags = !InITBlock(); | 
|  | 1107 | shift_t = SRType_LSL; | 
|  | 1108 | shift_n = 0; | 
|  | 1109 | if (InITBlock()) | 
|  | 1110 | return false; | 
|  | 1111 | break; | 
|  | 1112 | case eEncodingT2: | 
|  | 1113 | Rd = Bits32(opcode, 11, 8); | 
|  | 1114 | Rm = Bits32(opcode, 3, 0); | 
|  | 1115 | setflags = BitIsSet(opcode, 20); | 
| Johnny Chen | 3dd0605 | 2011-02-22 21:17:52 +0000 | [diff] [blame] | 1116 | shift_n = DecodeImmShiftThumb(opcode, shift_t); | 
| Johnny Chen | d642a6a | 2011-02-22 01:01:03 +0000 | [diff] [blame] | 1117 | // if (BadReg(d) || BadReg(m)) then UNPREDICTABLE; | 
| Johnny Chen | ed32e7c | 2011-02-22 23:42:58 +0000 | [diff] [blame] | 1118 | if (BadReg(Rd) || BadReg(Rm)) | 
| Johnny Chen | d642a6a | 2011-02-22 01:01:03 +0000 | [diff] [blame] | 1119 | return false; | 
| Johnny Chen | ed32e7c | 2011-02-22 23:42:58 +0000 | [diff] [blame] | 1120 | break; | 
| Johnny Chen | d642a6a | 2011-02-22 01:01:03 +0000 | [diff] [blame] | 1121 | case eEncodingA1: | 
|  | 1122 | Rd = Bits32(opcode, 15, 12); | 
|  | 1123 | Rm = Bits32(opcode, 3, 0); | 
|  | 1124 | setflags = BitIsSet(opcode, 20); | 
| Johnny Chen | 3dd0605 | 2011-02-22 21:17:52 +0000 | [diff] [blame] | 1125 | shift_n = DecodeImmShiftARM(opcode, shift_t); | 
| Johnny Chen | d642a6a | 2011-02-22 01:01:03 +0000 | [diff] [blame] | 1126 | break; | 
|  | 1127 | default: | 
|  | 1128 | return false; | 
|  | 1129 | } | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 1130 | bool success = false; | 
| Johnny Chen | d642a6a | 2011-02-22 01:01:03 +0000 | [diff] [blame] | 1131 | uint32_t value = ReadCoreReg(Rm, &success); | 
|  | 1132 | if (!success) | 
|  | 1133 | return false; | 
|  | 1134 |  | 
| Johnny Chen | a4438a7 | 2011-06-02 22:50:51 +0000 | [diff] [blame] | 1135 | uint32_t shifted = Shift_C(value, shift_t, shift_n, APSR_C, carry, &success); | 
|  | 1136 | if (!success) | 
|  | 1137 | return false; | 
| Johnny Chen | d642a6a | 2011-02-22 01:01:03 +0000 | [diff] [blame] | 1138 | uint32_t result = ~shifted; | 
|  | 1139 |  | 
|  | 1140 | // The context specifies that an immediate is to be moved into Rd. | 
|  | 1141 | EmulateInstruction::Context context; | 
|  | 1142 | context.type = EmulateInstruction::eContextImmediate; | 
|  | 1143 | context.SetNoArgs (); | 
|  | 1144 |  | 
|  | 1145 | if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry)) | 
|  | 1146 | return false; | 
|  | 1147 | } | 
|  | 1148 | return true; | 
|  | 1149 | } | 
|  | 1150 |  | 
| Johnny Chen | 788e055 | 2011-01-27 22:52:23 +0000 | [diff] [blame] | 1151 | // PC relative immediate load into register, possibly followed by ADD (SP plus register). | 
|  | 1152 | // LDR (literal) | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 1153 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 1154 | EmulateInstructionARM::EmulateLDRRtPCRelative (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | 788e055 | 2011-01-27 22:52:23 +0000 | [diff] [blame] | 1155 | { | 
|  | 1156 | #if 0 | 
|  | 1157 | // ARM pseudo code... | 
|  | 1158 | if (ConditionPassed()) | 
|  | 1159 | { | 
|  | 1160 | EncodingSpecificOperations(); NullCheckIfThumbEE(15); | 
|  | 1161 | base = Align(PC,4); | 
|  | 1162 | address = if add then (base + imm32) else (base - imm32); | 
|  | 1163 | data = MemU[address,4]; | 
|  | 1164 | if t == 15 then | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 1165 | if address<1:0> == '00' then LoadWritePC(data); else UNPREDICTABLE; | 
|  | 1166 | elsif UnalignedSupport() || address<1:0> = '00' then | 
| Johnny Chen | 788e055 | 2011-01-27 22:52:23 +0000 | [diff] [blame] | 1167 | R[t] = data; | 
|  | 1168 | else // Can only apply before ARMv7 | 
|  | 1169 | if CurrentInstrSet() == InstrSet_ARM then | 
|  | 1170 | R[t] = ROR(data, 8*UInt(address<1:0>)); | 
|  | 1171 | else | 
|  | 1172 | R[t] = bits(32) UNKNOWN; | 
|  | 1173 | } | 
|  | 1174 | #endif | 
|  | 1175 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 1176 | if (ConditionPassed(opcode)) | 
| Johnny Chen | 788e055 | 2011-01-27 22:52:23 +0000 | [diff] [blame] | 1177 | { | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 1178 | bool success = false; | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 1179 | const uint32_t pc = ReadCoreReg(PC_REG, &success); | 
| Johnny Chen | 788e055 | 2011-01-27 22:52:23 +0000 | [diff] [blame] | 1180 | if (!success) | 
|  | 1181 | return false; | 
| Johnny Chen | 809742e | 2011-01-28 00:32:27 +0000 | [diff] [blame] | 1182 |  | 
|  | 1183 | // PC relative immediate load context | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 1184 | EmulateInstruction::Context context; | 
|  | 1185 | context.type = EmulateInstruction::eContextRegisterPlusOffset; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 1186 | RegisterInfo pc_reg; | 
|  | 1187 | GetRegisterInfo (eRegisterKindDWARF, dwarf_pc, pc_reg); | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 1188 | context.SetRegisterPlusOffset (pc_reg, 0); | 
|  | 1189 |  | 
| Johnny Chen | c9de910 | 2011-02-11 19:12:30 +0000 | [diff] [blame] | 1190 | uint32_t Rt;    // the destination register | 
| Johnny Chen | 788e055 | 2011-01-27 22:52:23 +0000 | [diff] [blame] | 1191 | uint32_t imm32; // immediate offset from the PC | 
| Johnny Chen | c9de910 | 2011-02-11 19:12:30 +0000 | [diff] [blame] | 1192 | bool add;       // +imm32 or -imm32? | 
|  | 1193 | addr_t base;    // the base address | 
|  | 1194 | addr_t address; // the PC relative address | 
| Johnny Chen | 788e055 | 2011-01-27 22:52:23 +0000 | [diff] [blame] | 1195 | uint32_t data;  // the literal data value from the PC relative load | 
|  | 1196 | switch (encoding) { | 
|  | 1197 | case eEncodingT1: | 
| Johnny Chen | c9de910 | 2011-02-11 19:12:30 +0000 | [diff] [blame] | 1198 | Rt = Bits32(opcode, 10, 8); | 
| Johnny Chen | 788e055 | 2011-01-27 22:52:23 +0000 | [diff] [blame] | 1199 | imm32 = Bits32(opcode, 7, 0) << 2; // imm32 = ZeroExtend(imm8:'00', 32); | 
| Johnny Chen | c9de910 | 2011-02-11 19:12:30 +0000 | [diff] [blame] | 1200 | add = true; | 
| Johnny Chen | c9de910 | 2011-02-11 19:12:30 +0000 | [diff] [blame] | 1201 | break; | 
|  | 1202 | case eEncodingT2: | 
|  | 1203 | Rt = Bits32(opcode, 15, 12); | 
|  | 1204 | imm32 = Bits32(opcode, 11, 0) << 2; // imm32 = ZeroExtend(imm12, 32); | 
|  | 1205 | add = BitIsSet(opcode, 23); | 
| Johnny Chen | 098ae2d | 2011-02-12 00:50:05 +0000 | [diff] [blame] | 1206 | if (Rt == 15 && InITBlock() && !LastInITBlock()) | 
| Johnny Chen | c9de910 | 2011-02-11 19:12:30 +0000 | [diff] [blame] | 1207 | return false; | 
| Johnny Chen | 788e055 | 2011-01-27 22:52:23 +0000 | [diff] [blame] | 1208 | break; | 
|  | 1209 | default: | 
|  | 1210 | return false; | 
|  | 1211 | } | 
| Johnny Chen | c9de910 | 2011-02-11 19:12:30 +0000 | [diff] [blame] | 1212 |  | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 1213 | base = Align(pc, 4); | 
| Johnny Chen | c9de910 | 2011-02-11 19:12:30 +0000 | [diff] [blame] | 1214 | if (add) | 
|  | 1215 | address = base + imm32; | 
|  | 1216 | else | 
|  | 1217 | address = base - imm32; | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 1218 |  | 
|  | 1219 | context.SetRegisterPlusOffset(pc_reg, address - base); | 
| Caroline Tice | cc96eb5 | 2011-02-17 19:20:40 +0000 | [diff] [blame] | 1220 | data = MemURead(context, address, 4, 0, &success); | 
| Johnny Chen | 788e055 | 2011-01-27 22:52:23 +0000 | [diff] [blame] | 1221 | if (!success) | 
| Johnny Chen | 809742e | 2011-01-28 00:32:27 +0000 | [diff] [blame] | 1222 | return false; | 
| Johnny Chen | c9de910 | 2011-02-11 19:12:30 +0000 | [diff] [blame] | 1223 |  | 
|  | 1224 | if (Rt == 15) | 
|  | 1225 | { | 
|  | 1226 | if (Bits32(address, 1, 0) == 0) | 
|  | 1227 | { | 
|  | 1228 | // In ARMv5T and above, this is an interworking branch. | 
| Johnny Chen | 668b451 | 2011-02-15 21:08:58 +0000 | [diff] [blame] | 1229 | if (!LoadWritePC(context, data)) | 
| Johnny Chen | c9de910 | 2011-02-11 19:12:30 +0000 | [diff] [blame] | 1230 | return false; | 
|  | 1231 | } | 
|  | 1232 | else | 
|  | 1233 | return false; | 
|  | 1234 | } | 
|  | 1235 | else if (UnalignedSupport() || Bits32(address, 1, 0) == 0) | 
|  | 1236 | { | 
|  | 1237 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rt, data)) | 
|  | 1238 | return false; | 
|  | 1239 | } | 
|  | 1240 | else // We don't handle ARM for now. | 
|  | 1241 | return false; | 
|  | 1242 |  | 
| Johnny Chen | 788e055 | 2011-01-27 22:52:23 +0000 | [diff] [blame] | 1243 | } | 
|  | 1244 | return true; | 
|  | 1245 | } | 
|  | 1246 |  | 
| Johnny Chen | 5b442b7 | 2011-01-27 19:34:30 +0000 | [diff] [blame] | 1247 | // An add operation to adjust the SP. | 
| Johnny Chen | fdd179e | 2011-01-31 20:09:28 +0000 | [diff] [blame] | 1248 | // ADD (SP plus immediate) | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 1249 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 1250 | EmulateInstructionARM::EmulateADDSPImm (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | fdd179e | 2011-01-31 20:09:28 +0000 | [diff] [blame] | 1251 | { | 
|  | 1252 | #if 0 | 
|  | 1253 | // ARM pseudo code... | 
|  | 1254 | if (ConditionPassed()) | 
|  | 1255 | { | 
|  | 1256 | EncodingSpecificOperations(); | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 1257 | (result, carry, overflow) = AddWithCarry(SP, imm32, '0'); | 
| Johnny Chen | fdd179e | 2011-01-31 20:09:28 +0000 | [diff] [blame] | 1258 | if d == 15 then // Can only occur for ARM encoding | 
|  | 1259 | ALUWritePC(result); // setflags is always FALSE here | 
|  | 1260 | else | 
|  | 1261 | R[d] = result; | 
|  | 1262 | if setflags then | 
|  | 1263 | APSR.N = result<31>; | 
|  | 1264 | APSR.Z = IsZeroBit(result); | 
|  | 1265 | APSR.C = carry; | 
|  | 1266 | APSR.V = overflow; | 
|  | 1267 | } | 
|  | 1268 | #endif | 
|  | 1269 |  | 
|  | 1270 | bool success = false; | 
| Johnny Chen | fdd179e | 2011-01-31 20:09:28 +0000 | [diff] [blame] | 1271 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 1272 | if (ConditionPassed(opcode)) | 
| Johnny Chen | fdd179e | 2011-01-31 20:09:28 +0000 | [diff] [blame] | 1273 | { | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 1274 | const addr_t sp = ReadCoreReg (SP_REG, &success); | 
| Johnny Chen | fdd179e | 2011-01-31 20:09:28 +0000 | [diff] [blame] | 1275 | if (!success) | 
|  | 1276 | return false; | 
|  | 1277 | uint32_t imm32; // the immediate operand | 
| Caroline Tice | e221288 | 2011-03-22 22:38:28 +0000 | [diff] [blame] | 1278 | uint32_t d; | 
|  | 1279 | bool setflags; | 
|  | 1280 | switch (encoding) | 
|  | 1281 | { | 
|  | 1282 | case eEncodingT1: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 1283 | // d = UInt(Rd); setflags = FALSE; imm32 = ZeroExtend(imm8:'00', 32); | 
| Caroline Tice | e221288 | 2011-03-22 22:38:28 +0000 | [diff] [blame] | 1284 | d = Bits32 (opcode, 10, 8); | 
|  | 1285 | setflags = false; | 
|  | 1286 | imm32 = (Bits32 (opcode, 7, 0) << 2); | 
|  | 1287 |  | 
|  | 1288 | break; | 
|  | 1289 |  | 
|  | 1290 | case eEncodingT2: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 1291 | // d = 13; setflags = FALSE; imm32 = ZeroExtend(imm7:'00', 32); | 
| Caroline Tice | e221288 | 2011-03-22 22:38:28 +0000 | [diff] [blame] | 1292 | d = 13; | 
|  | 1293 | setflags = false; | 
|  | 1294 | imm32 = ThumbImm7Scaled(opcode); // imm32 = ZeroExtend(imm7:'00', 32) | 
|  | 1295 |  | 
|  | 1296 | break; | 
|  | 1297 |  | 
|  | 1298 | default: | 
|  | 1299 | return false; | 
| Johnny Chen | fdd179e | 2011-01-31 20:09:28 +0000 | [diff] [blame] | 1300 | } | 
|  | 1301 | addr_t sp_offset = imm32; | 
|  | 1302 | addr_t addr = sp + sp_offset; // the adjusted stack pointer value | 
|  | 1303 |  | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 1304 | EmulateInstruction::Context context; | 
|  | 1305 | context.type = EmulateInstruction::eContextAdjustStackPointer; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 1306 | RegisterInfo sp_reg; | 
|  | 1307 | GetRegisterInfo (eRegisterKindDWARF, dwarf_sp, sp_reg); | 
| Caroline Tice | 080bf61 | 2011-04-05 18:46:00 +0000 | [diff] [blame] | 1308 | context.SetRegisterPlusOffset (sp_reg, sp_offset); | 
| Johnny Chen | fdd179e | 2011-01-31 20:09:28 +0000 | [diff] [blame] | 1309 |  | 
| Caroline Tice | e221288 | 2011-03-22 22:38:28 +0000 | [diff] [blame] | 1310 | if (d == 15) | 
|  | 1311 | { | 
|  | 1312 | if (!ALUWritePC (context, addr)) | 
|  | 1313 | return false; | 
|  | 1314 | } | 
|  | 1315 | else | 
|  | 1316 | { | 
|  | 1317 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + d, addr)) | 
|  | 1318 | return false; | 
|  | 1319 | } | 
| Johnny Chen | fdd179e | 2011-01-31 20:09:28 +0000 | [diff] [blame] | 1320 | } | 
|  | 1321 | return true; | 
|  | 1322 | } | 
|  | 1323 |  | 
|  | 1324 | // An add operation to adjust the SP. | 
| Johnny Chen | 5b442b7 | 2011-01-27 19:34:30 +0000 | [diff] [blame] | 1325 | // ADD (SP plus register) | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 1326 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 1327 | EmulateInstructionARM::EmulateADDSPRm (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | 5b442b7 | 2011-01-27 19:34:30 +0000 | [diff] [blame] | 1328 | { | 
|  | 1329 | #if 0 | 
|  | 1330 | // ARM pseudo code... | 
|  | 1331 | if (ConditionPassed()) | 
|  | 1332 | { | 
|  | 1333 | EncodingSpecificOperations(); | 
|  | 1334 | shifted = Shift(R[m], shift_t, shift_n, APSR.C); | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 1335 | (result, carry, overflow) = AddWithCarry(SP, shifted, '0'); | 
| Johnny Chen | 5b442b7 | 2011-01-27 19:34:30 +0000 | [diff] [blame] | 1336 | if d == 15 then | 
|  | 1337 | ALUWritePC(result); // setflags is always FALSE here | 
|  | 1338 | else | 
|  | 1339 | R[d] = result; | 
|  | 1340 | if setflags then | 
|  | 1341 | APSR.N = result<31>; | 
|  | 1342 | APSR.Z = IsZeroBit(result); | 
|  | 1343 | APSR.C = carry; | 
|  | 1344 | APSR.V = overflow; | 
|  | 1345 | } | 
|  | 1346 | #endif | 
|  | 1347 |  | 
|  | 1348 | bool success = false; | 
| Johnny Chen | 5b442b7 | 2011-01-27 19:34:30 +0000 | [diff] [blame] | 1349 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 1350 | if (ConditionPassed(opcode)) | 
| Johnny Chen | 5b442b7 | 2011-01-27 19:34:30 +0000 | [diff] [blame] | 1351 | { | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 1352 | const addr_t sp = ReadCoreReg (SP_REG, &success); | 
| Johnny Chen | 5b442b7 | 2011-01-27 19:34:30 +0000 | [diff] [blame] | 1353 | if (!success) | 
|  | 1354 | return false; | 
|  | 1355 | uint32_t Rm; // the second operand | 
|  | 1356 | switch (encoding) { | 
|  | 1357 | case eEncodingT2: | 
|  | 1358 | Rm = Bits32(opcode, 6, 3); | 
|  | 1359 | break; | 
|  | 1360 | default: | 
|  | 1361 | return false; | 
|  | 1362 | } | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 1363 | int32_t reg_value = ReadCoreReg(Rm, &success); | 
| Johnny Chen | 5b442b7 | 2011-01-27 19:34:30 +0000 | [diff] [blame] | 1364 | if (!success) | 
|  | 1365 | return false; | 
|  | 1366 |  | 
|  | 1367 | addr_t addr = (int32_t)sp + reg_value; // the adjusted stack pointer value | 
|  | 1368 |  | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 1369 | EmulateInstruction::Context context; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 1370 | context.type = eContextArithmetic; | 
|  | 1371 | RegisterInfo sp_reg; | 
|  | 1372 | GetRegisterInfo (eRegisterKindDWARF, dwarf_sp, sp_reg); | 
|  | 1373 |  | 
|  | 1374 | RegisterInfo other_reg; | 
|  | 1375 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + Rm, other_reg); | 
| Caroline Tice | 080bf61 | 2011-04-05 18:46:00 +0000 | [diff] [blame] | 1376 | context.SetRegisterRegisterOperands (sp_reg, other_reg); | 
| Johnny Chen | 5b442b7 | 2011-01-27 19:34:30 +0000 | [diff] [blame] | 1377 |  | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 1378 | if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, addr)) | 
| Johnny Chen | 5b442b7 | 2011-01-27 19:34:30 +0000 | [diff] [blame] | 1379 | return false; | 
|  | 1380 | } | 
|  | 1381 | return true; | 
|  | 1382 | } | 
|  | 1383 |  | 
| Johnny Chen | 9b8d783 | 2011-02-02 01:13:56 +0000 | [diff] [blame] | 1384 | // Branch with Link and Exchange Instruction Sets (immediate) calls a subroutine | 
|  | 1385 | // at a PC-relative address, and changes instruction set from ARM to Thumb, or | 
|  | 1386 | // from Thumb to ARM. | 
|  | 1387 | // BLX (immediate) | 
|  | 1388 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 1389 | EmulateInstructionARM::EmulateBLXImmediate (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | 9b8d783 | 2011-02-02 01:13:56 +0000 | [diff] [blame] | 1390 | { | 
|  | 1391 | #if 0 | 
|  | 1392 | // ARM pseudo code... | 
|  | 1393 | if (ConditionPassed()) | 
|  | 1394 | { | 
|  | 1395 | EncodingSpecificOperations(); | 
|  | 1396 | if CurrentInstrSet() == InstrSet_ARM then | 
|  | 1397 | LR = PC - 4; | 
|  | 1398 | else | 
|  | 1399 | LR = PC<31:1> : '1'; | 
|  | 1400 | if targetInstrSet == InstrSet_ARM then | 
|  | 1401 | targetAddress = Align(PC,4) + imm32; | 
|  | 1402 | else | 
|  | 1403 | targetAddress = PC + imm32; | 
|  | 1404 | SelectInstrSet(targetInstrSet); | 
|  | 1405 | BranchWritePC(targetAddress); | 
|  | 1406 | } | 
|  | 1407 | #endif | 
|  | 1408 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 1409 | bool success = true; | 
| Johnny Chen | 9b8d783 | 2011-02-02 01:13:56 +0000 | [diff] [blame] | 1410 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 1411 | if (ConditionPassed(opcode)) | 
| Johnny Chen | 9b8d783 | 2011-02-02 01:13:56 +0000 | [diff] [blame] | 1412 | { | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 1413 | EmulateInstruction::Context context; | 
|  | 1414 | context.type = EmulateInstruction::eContextRelativeBranchImmediate; | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 1415 | const uint32_t pc = ReadCoreReg(PC_REG, &success); | 
| Johnny Chen | 9b8d783 | 2011-02-02 01:13:56 +0000 | [diff] [blame] | 1416 | if (!success) | 
|  | 1417 | return false; | 
| Johnny Chen | 53ebab7 | 2011-02-08 23:21:57 +0000 | [diff] [blame] | 1418 | addr_t lr; // next instruction address | 
|  | 1419 | addr_t target; // target address | 
| Johnny Chen | 9b8d783 | 2011-02-02 01:13:56 +0000 | [diff] [blame] | 1420 | int32_t imm32; // PC-relative offset | 
|  | 1421 | switch (encoding) { | 
| Johnny Chen | d6c13f0 | 2011-02-08 20:36:34 +0000 | [diff] [blame] | 1422 | case eEncodingT1: | 
|  | 1423 | { | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 1424 | lr = pc | 1u; // return address | 
| Johnny Chen | bd59990 | 2011-02-10 21:39:01 +0000 | [diff] [blame] | 1425 | uint32_t S = Bit32(opcode, 26); | 
| Johnny Chen | d6c13f0 | 2011-02-08 20:36:34 +0000 | [diff] [blame] | 1426 | uint32_t imm10 = Bits32(opcode, 25, 16); | 
| Johnny Chen | bd59990 | 2011-02-10 21:39:01 +0000 | [diff] [blame] | 1427 | uint32_t J1 = Bit32(opcode, 13); | 
|  | 1428 | uint32_t J2 = Bit32(opcode, 11); | 
| Johnny Chen | d6c13f0 | 2011-02-08 20:36:34 +0000 | [diff] [blame] | 1429 | uint32_t imm11 = Bits32(opcode, 10, 0); | 
|  | 1430 | uint32_t I1 = !(J1 ^ S); | 
|  | 1431 | uint32_t I2 = !(J2 ^ S); | 
| Johnny Chen | 53ebab7 | 2011-02-08 23:21:57 +0000 | [diff] [blame] | 1432 | uint32_t imm25 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1); | 
| Johnny Chen | d6c13f0 | 2011-02-08 20:36:34 +0000 | [diff] [blame] | 1433 | imm32 = llvm::SignExtend32<25>(imm25); | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 1434 | target = pc + imm32; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 1435 | context.SetISAAndImmediateSigned (eModeThumb, 4 + imm32); | 
| Johnny Chen | 098ae2d | 2011-02-12 00:50:05 +0000 | [diff] [blame] | 1436 | if (InITBlock() && !LastInITBlock()) | 
| Johnny Chen | ab3b351 | 2011-02-12 00:10:51 +0000 | [diff] [blame] | 1437 | return false; | 
| Johnny Chen | d6c13f0 | 2011-02-08 20:36:34 +0000 | [diff] [blame] | 1438 | break; | 
|  | 1439 | } | 
| Johnny Chen | 9b8d783 | 2011-02-02 01:13:56 +0000 | [diff] [blame] | 1440 | case eEncodingT2: | 
|  | 1441 | { | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 1442 | lr = pc | 1u; // return address | 
| Johnny Chen | bd59990 | 2011-02-10 21:39:01 +0000 | [diff] [blame] | 1443 | uint32_t S = Bit32(opcode, 26); | 
| Johnny Chen | 9b8d783 | 2011-02-02 01:13:56 +0000 | [diff] [blame] | 1444 | uint32_t imm10H = Bits32(opcode, 25, 16); | 
| Johnny Chen | bd59990 | 2011-02-10 21:39:01 +0000 | [diff] [blame] | 1445 | uint32_t J1 = Bit32(opcode, 13); | 
|  | 1446 | uint32_t J2 = Bit32(opcode, 11); | 
| Johnny Chen | 9b8d783 | 2011-02-02 01:13:56 +0000 | [diff] [blame] | 1447 | uint32_t imm10L = Bits32(opcode, 10, 1); | 
|  | 1448 | uint32_t I1 = !(J1 ^ S); | 
|  | 1449 | uint32_t I2 = !(J2 ^ S); | 
| Johnny Chen | 53ebab7 | 2011-02-08 23:21:57 +0000 | [diff] [blame] | 1450 | uint32_t imm25 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10H << 12) | (imm10L << 2); | 
| Johnny Chen | 9b8d783 | 2011-02-02 01:13:56 +0000 | [diff] [blame] | 1451 | imm32 = llvm::SignExtend32<25>(imm25); | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 1452 | target = Align(pc, 4) + imm32; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 1453 | context.SetISAAndImmediateSigned (eModeARM, 4 + imm32); | 
| Johnny Chen | 098ae2d | 2011-02-12 00:50:05 +0000 | [diff] [blame] | 1454 | if (InITBlock() && !LastInITBlock()) | 
| Johnny Chen | ab3b351 | 2011-02-12 00:10:51 +0000 | [diff] [blame] | 1455 | return false; | 
| Johnny Chen | 9b8d783 | 2011-02-02 01:13:56 +0000 | [diff] [blame] | 1456 | break; | 
|  | 1457 | } | 
| Johnny Chen | c47d0ca | 2011-02-08 18:58:31 +0000 | [diff] [blame] | 1458 | case eEncodingA1: | 
| Caroline Tice | 2b03ed8 | 2011-03-16 00:06:12 +0000 | [diff] [blame] | 1459 | lr = pc - 4; // return address | 
| Johnny Chen | c47d0ca | 2011-02-08 18:58:31 +0000 | [diff] [blame] | 1460 | imm32 = llvm::SignExtend32<26>(Bits32(opcode, 23, 0) << 2); | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 1461 | target = Align(pc, 4) + imm32; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 1462 | context.SetISAAndImmediateSigned (eModeARM, 8 + imm32); | 
| Johnny Chen | c47d0ca | 2011-02-08 18:58:31 +0000 | [diff] [blame] | 1463 | break; | 
| Johnny Chen | 9b8d783 | 2011-02-02 01:13:56 +0000 | [diff] [blame] | 1464 | case eEncodingA2: | 
| Caroline Tice | 2b03ed8 | 2011-03-16 00:06:12 +0000 | [diff] [blame] | 1465 | lr = pc - 4; // return address | 
| Johnny Chen | 9b8d783 | 2011-02-02 01:13:56 +0000 | [diff] [blame] | 1466 | imm32 = llvm::SignExtend32<26>(Bits32(opcode, 23, 0) << 2 | Bits32(opcode, 24, 24) << 1); | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 1467 | target = pc + imm32; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 1468 | context.SetISAAndImmediateSigned (eModeThumb, 8 + imm32); | 
| Johnny Chen | 9b8d783 | 2011-02-02 01:13:56 +0000 | [diff] [blame] | 1469 | break; | 
|  | 1470 | default: | 
|  | 1471 | return false; | 
|  | 1472 | } | 
|  | 1473 | if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, lr)) | 
|  | 1474 | return false; | 
| Johnny Chen | 9ee056b | 2011-02-08 00:06:35 +0000 | [diff] [blame] | 1475 | if (!BranchWritePC(context, target)) | 
| Johnny Chen | 9b8d783 | 2011-02-02 01:13:56 +0000 | [diff] [blame] | 1476 | return false; | 
|  | 1477 | } | 
|  | 1478 | return true; | 
|  | 1479 | } | 
|  | 1480 |  | 
|  | 1481 | // Branch with Link and Exchange (register) calls a subroutine at an address and | 
|  | 1482 | // instruction set specified by a register. | 
|  | 1483 | // BLX (register) | 
|  | 1484 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 1485 | EmulateInstructionARM::EmulateBLXRm (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | 9b8d783 | 2011-02-02 01:13:56 +0000 | [diff] [blame] | 1486 | { | 
|  | 1487 | #if 0 | 
|  | 1488 | // ARM pseudo code... | 
|  | 1489 | if (ConditionPassed()) | 
|  | 1490 | { | 
|  | 1491 | EncodingSpecificOperations(); | 
|  | 1492 | target = R[m]; | 
|  | 1493 | if CurrentInstrSet() == InstrSet_ARM then | 
|  | 1494 | next_instr_addr = PC - 4; | 
|  | 1495 | LR = next_instr_addr; | 
|  | 1496 | else | 
|  | 1497 | next_instr_addr = PC - 2; | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 1498 | LR = next_instr_addr<31:1> : '1'; | 
| Johnny Chen | 9b8d783 | 2011-02-02 01:13:56 +0000 | [diff] [blame] | 1499 | BXWritePC(target); | 
|  | 1500 | } | 
|  | 1501 | #endif | 
|  | 1502 |  | 
|  | 1503 | bool success = false; | 
| Johnny Chen | 9b8d783 | 2011-02-02 01:13:56 +0000 | [diff] [blame] | 1504 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 1505 | if (ConditionPassed(opcode)) | 
| Johnny Chen | 9b8d783 | 2011-02-02 01:13:56 +0000 | [diff] [blame] | 1506 | { | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 1507 | EmulateInstruction::Context context; | 
|  | 1508 | context.type = EmulateInstruction::eContextAbsoluteBranchRegister; | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 1509 | const uint32_t pc = ReadCoreReg(PC_REG, &success); | 
| Johnny Chen | 9b8d783 | 2011-02-02 01:13:56 +0000 | [diff] [blame] | 1510 | addr_t lr; // next instruction address | 
| Johnny Chen | 9b8d783 | 2011-02-02 01:13:56 +0000 | [diff] [blame] | 1511 | if (!success) | 
|  | 1512 | return false; | 
|  | 1513 | uint32_t Rm; // the register with the target address | 
|  | 1514 | switch (encoding) { | 
|  | 1515 | case eEncodingT1: | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 1516 | lr = (pc - 2) | 1u; // return address | 
| Johnny Chen | 9b8d783 | 2011-02-02 01:13:56 +0000 | [diff] [blame] | 1517 | Rm = Bits32(opcode, 6, 3); | 
|  | 1518 | // if m == 15 then UNPREDICTABLE; | 
|  | 1519 | if (Rm == 15) | 
|  | 1520 | return false; | 
| Johnny Chen | 098ae2d | 2011-02-12 00:50:05 +0000 | [diff] [blame] | 1521 | if (InITBlock() && !LastInITBlock()) | 
| Johnny Chen | ab3b351 | 2011-02-12 00:10:51 +0000 | [diff] [blame] | 1522 | return false; | 
| Johnny Chen | 9b8d783 | 2011-02-02 01:13:56 +0000 | [diff] [blame] | 1523 | break; | 
|  | 1524 | case eEncodingA1: | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 1525 | lr = pc - 4; // return address | 
| Johnny Chen | 9b8d783 | 2011-02-02 01:13:56 +0000 | [diff] [blame] | 1526 | Rm = Bits32(opcode, 3, 0); | 
|  | 1527 | // if m == 15 then UNPREDICTABLE; | 
|  | 1528 | if (Rm == 15) | 
|  | 1529 | return false; | 
| Johnny Chen | b77be41 | 2011-02-04 00:40:18 +0000 | [diff] [blame] | 1530 | break; | 
| Johnny Chen | 9b8d783 | 2011-02-02 01:13:56 +0000 | [diff] [blame] | 1531 | default: | 
|  | 1532 | return false; | 
|  | 1533 | } | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 1534 | addr_t target = ReadCoreReg (Rm, &success); | 
| Johnny Chen | ab3b351 | 2011-02-12 00:10:51 +0000 | [diff] [blame] | 1535 | if (!success) | 
|  | 1536 | return false; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 1537 | RegisterInfo dwarf_reg; | 
|  | 1538 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + Rm, dwarf_reg); | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 1539 | context.SetRegister (dwarf_reg); | 
| Johnny Chen | 9b8d783 | 2011-02-02 01:13:56 +0000 | [diff] [blame] | 1540 | if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, lr)) | 
|  | 1541 | return false; | 
| Johnny Chen | 668b451 | 2011-02-15 21:08:58 +0000 | [diff] [blame] | 1542 | if (!BXWritePC(context, target)) | 
| Johnny Chen | 9b8d783 | 2011-02-02 01:13:56 +0000 | [diff] [blame] | 1543 | return false; | 
|  | 1544 | } | 
|  | 1545 | return true; | 
|  | 1546 | } | 
|  | 1547 |  | 
| Johnny Chen | ab3b351 | 2011-02-12 00:10:51 +0000 | [diff] [blame] | 1548 | // Branch and Exchange causes a branch to an address and instruction set specified by a register. | 
| Johnny Chen | ab3b351 | 2011-02-12 00:10:51 +0000 | [diff] [blame] | 1549 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 1550 | EmulateInstructionARM::EmulateBXRm (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | ab3b351 | 2011-02-12 00:10:51 +0000 | [diff] [blame] | 1551 | { | 
|  | 1552 | #if 0 | 
|  | 1553 | // ARM pseudo code... | 
|  | 1554 | if (ConditionPassed()) | 
|  | 1555 | { | 
|  | 1556 | EncodingSpecificOperations(); | 
|  | 1557 | BXWritePC(R[m]); | 
|  | 1558 | } | 
|  | 1559 | #endif | 
|  | 1560 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 1561 | if (ConditionPassed(opcode)) | 
| Johnny Chen | ab3b351 | 2011-02-12 00:10:51 +0000 | [diff] [blame] | 1562 | { | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 1563 | EmulateInstruction::Context context; | 
|  | 1564 | context.type = EmulateInstruction::eContextAbsoluteBranchRegister; | 
| Johnny Chen | ab3b351 | 2011-02-12 00:10:51 +0000 | [diff] [blame] | 1565 | uint32_t Rm; // the register with the target address | 
|  | 1566 | switch (encoding) { | 
|  | 1567 | case eEncodingT1: | 
|  | 1568 | Rm = Bits32(opcode, 6, 3); | 
| Johnny Chen | 098ae2d | 2011-02-12 00:50:05 +0000 | [diff] [blame] | 1569 | if (InITBlock() && !LastInITBlock()) | 
| Johnny Chen | ab3b351 | 2011-02-12 00:10:51 +0000 | [diff] [blame] | 1570 | return false; | 
|  | 1571 | break; | 
|  | 1572 | case eEncodingA1: | 
|  | 1573 | Rm = Bits32(opcode, 3, 0); | 
|  | 1574 | break; | 
|  | 1575 | default: | 
|  | 1576 | return false; | 
|  | 1577 | } | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 1578 | bool success = false; | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 1579 | addr_t target = ReadCoreReg (Rm, &success); | 
| Johnny Chen | ab3b351 | 2011-02-12 00:10:51 +0000 | [diff] [blame] | 1580 | if (!success) | 
|  | 1581 | return false; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 1582 |  | 
|  | 1583 | RegisterInfo dwarf_reg; | 
|  | 1584 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + Rm, dwarf_reg); | 
| Johnny Chen | 668b451 | 2011-02-15 21:08:58 +0000 | [diff] [blame] | 1585 | context.SetRegister (dwarf_reg); | 
|  | 1586 | if (!BXWritePC(context, target)) | 
| Johnny Chen | ab3b351 | 2011-02-12 00:10:51 +0000 | [diff] [blame] | 1587 | return false; | 
|  | 1588 | } | 
|  | 1589 | return true; | 
|  | 1590 | } | 
|  | 1591 |  | 
| Johnny Chen | 59e6ab7 | 2011-02-24 21:01:20 +0000 | [diff] [blame] | 1592 | // Branch and Exchange Jazelle attempts to change to Jazelle state. If the attempt fails, it branches to an | 
|  | 1593 | // address and instruction set specified by a register as though it were a BX instruction. | 
|  | 1594 | // | 
|  | 1595 | // TODO: Emulate Jazelle architecture? | 
|  | 1596 | //       We currently assume that switching to Jazelle state fails, thus treating BXJ as a BX operation. | 
|  | 1597 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 1598 | EmulateInstructionARM::EmulateBXJRm (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | 59e6ab7 | 2011-02-24 21:01:20 +0000 | [diff] [blame] | 1599 | { | 
|  | 1600 | #if 0 | 
|  | 1601 | // ARM pseudo code... | 
|  | 1602 | if (ConditionPassed()) | 
|  | 1603 | { | 
|  | 1604 | EncodingSpecificOperations(); | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 1605 | if JMCR.JE == '0' || CurrentInstrSet() == InstrSet_ThumbEE then | 
| Johnny Chen | 59e6ab7 | 2011-02-24 21:01:20 +0000 | [diff] [blame] | 1606 | BXWritePC(R[m]); | 
|  | 1607 | else | 
|  | 1608 | if JazelleAcceptsExecution() then | 
|  | 1609 | SwitchToJazelleExecution(); | 
|  | 1610 | else | 
|  | 1611 | SUBARCHITECTURE_DEFINED handler call; | 
|  | 1612 | } | 
|  | 1613 | #endif | 
|  | 1614 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 1615 | if (ConditionPassed(opcode)) | 
| Johnny Chen | 59e6ab7 | 2011-02-24 21:01:20 +0000 | [diff] [blame] | 1616 | { | 
|  | 1617 | EmulateInstruction::Context context; | 
|  | 1618 | context.type = EmulateInstruction::eContextAbsoluteBranchRegister; | 
|  | 1619 | uint32_t Rm; // the register with the target address | 
|  | 1620 | switch (encoding) { | 
|  | 1621 | case eEncodingT1: | 
|  | 1622 | Rm = Bits32(opcode, 19, 16); | 
|  | 1623 | if (BadReg(Rm)) | 
|  | 1624 | return false; | 
|  | 1625 | if (InITBlock() && !LastInITBlock()) | 
|  | 1626 | return false; | 
|  | 1627 | break; | 
|  | 1628 | case eEncodingA1: | 
|  | 1629 | Rm = Bits32(opcode, 3, 0); | 
|  | 1630 | if (Rm == 15) | 
|  | 1631 | return false; | 
|  | 1632 | break; | 
|  | 1633 | default: | 
|  | 1634 | return false; | 
|  | 1635 | } | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 1636 | bool success = false; | 
| Johnny Chen | 59e6ab7 | 2011-02-24 21:01:20 +0000 | [diff] [blame] | 1637 | addr_t target = ReadCoreReg (Rm, &success); | 
|  | 1638 | if (!success) | 
|  | 1639 | return false; | 
|  | 1640 |  | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 1641 | RegisterInfo dwarf_reg; | 
|  | 1642 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + Rm, dwarf_reg); | 
| Johnny Chen | 59e6ab7 | 2011-02-24 21:01:20 +0000 | [diff] [blame] | 1643 | context.SetRegister (dwarf_reg); | 
|  | 1644 | if (!BXWritePC(context, target)) | 
|  | 1645 | return false; | 
|  | 1646 | } | 
|  | 1647 | return true; | 
|  | 1648 | } | 
|  | 1649 |  | 
| Johnny Chen | 0d0148e | 2011-01-28 02:26:08 +0000 | [diff] [blame] | 1650 | // Set r7 to point to some ip offset. | 
|  | 1651 | // SUB (immediate) | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 1652 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 1653 | EmulateInstructionARM::EmulateSUBR7IPImm (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | 0d0148e | 2011-01-28 02:26:08 +0000 | [diff] [blame] | 1654 | { | 
|  | 1655 | #if 0 | 
|  | 1656 | // ARM pseudo code... | 
|  | 1657 | if (ConditionPassed()) | 
|  | 1658 | { | 
|  | 1659 | EncodingSpecificOperations(); | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 1660 | (result, carry, overflow) = AddWithCarry(SP, NOT(imm32), '1'); | 
| Johnny Chen | 0d0148e | 2011-01-28 02:26:08 +0000 | [diff] [blame] | 1661 | if d == 15 then // Can only occur for ARM encoding | 
|  | 1662 | ALUWritePC(result); // setflags is always FALSE here | 
|  | 1663 | else | 
|  | 1664 | R[d] = result; | 
|  | 1665 | if setflags then | 
|  | 1666 | APSR.N = result<31>; | 
|  | 1667 | APSR.Z = IsZeroBit(result); | 
|  | 1668 | APSR.C = carry; | 
|  | 1669 | APSR.V = overflow; | 
|  | 1670 | } | 
|  | 1671 | #endif | 
|  | 1672 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 1673 | if (ConditionPassed(opcode)) | 
| Johnny Chen | 0d0148e | 2011-01-28 02:26:08 +0000 | [diff] [blame] | 1674 | { | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 1675 | bool success = false; | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 1676 | const addr_t ip = ReadCoreReg (12, &success); | 
| Johnny Chen | 0d0148e | 2011-01-28 02:26:08 +0000 | [diff] [blame] | 1677 | if (!success) | 
|  | 1678 | return false; | 
|  | 1679 | uint32_t imm32; | 
|  | 1680 | switch (encoding) { | 
|  | 1681 | case eEncodingA1: | 
|  | 1682 | imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12) | 
|  | 1683 | break; | 
|  | 1684 | default: | 
|  | 1685 | return false; | 
|  | 1686 | } | 
|  | 1687 | addr_t ip_offset = imm32; | 
|  | 1688 | addr_t addr = ip - ip_offset; // the adjusted ip value | 
|  | 1689 |  | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 1690 | EmulateInstruction::Context context; | 
|  | 1691 | context.type = EmulateInstruction::eContextRegisterPlusOffset; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 1692 | RegisterInfo dwarf_reg; | 
|  | 1693 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r12, dwarf_reg); | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 1694 | context.SetRegisterPlusOffset (dwarf_reg, -ip_offset); | 
| Johnny Chen | 0d0148e | 2011-01-28 02:26:08 +0000 | [diff] [blame] | 1695 |  | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 1696 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r7, addr)) | 
| Johnny Chen | 0d0148e | 2011-01-28 02:26:08 +0000 | [diff] [blame] | 1697 | return false; | 
|  | 1698 | } | 
|  | 1699 | return true; | 
|  | 1700 | } | 
|  | 1701 |  | 
|  | 1702 | // Set ip to point to some stack offset. | 
|  | 1703 | // SUB (SP minus immediate) | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 1704 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 1705 | EmulateInstructionARM::EmulateSUBIPSPImm (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | 0d0148e | 2011-01-28 02:26:08 +0000 | [diff] [blame] | 1706 | { | 
|  | 1707 | #if 0 | 
|  | 1708 | // ARM pseudo code... | 
|  | 1709 | if (ConditionPassed()) | 
|  | 1710 | { | 
|  | 1711 | EncodingSpecificOperations(); | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 1712 | (result, carry, overflow) = AddWithCarry(SP, NOT(imm32), '1'); | 
| Johnny Chen | 0d0148e | 2011-01-28 02:26:08 +0000 | [diff] [blame] | 1713 | if d == 15 then // Can only occur for ARM encoding | 
|  | 1714 | ALUWritePC(result); // setflags is always FALSE here | 
|  | 1715 | else | 
|  | 1716 | R[d] = result; | 
|  | 1717 | if setflags then | 
|  | 1718 | APSR.N = result<31>; | 
|  | 1719 | APSR.Z = IsZeroBit(result); | 
|  | 1720 | APSR.C = carry; | 
|  | 1721 | APSR.V = overflow; | 
|  | 1722 | } | 
|  | 1723 | #endif | 
|  | 1724 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 1725 | if (ConditionPassed(opcode)) | 
| Johnny Chen | 0d0148e | 2011-01-28 02:26:08 +0000 | [diff] [blame] | 1726 | { | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 1727 | bool success = false; | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 1728 | const addr_t sp = ReadCoreReg (SP_REG, &success); | 
| Johnny Chen | 0d0148e | 2011-01-28 02:26:08 +0000 | [diff] [blame] | 1729 | if (!success) | 
|  | 1730 | return false; | 
|  | 1731 | uint32_t imm32; | 
|  | 1732 | switch (encoding) { | 
|  | 1733 | case eEncodingA1: | 
|  | 1734 | imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12) | 
|  | 1735 | break; | 
|  | 1736 | default: | 
|  | 1737 | return false; | 
|  | 1738 | } | 
|  | 1739 | addr_t sp_offset = imm32; | 
|  | 1740 | addr_t addr = sp - sp_offset; // the adjusted stack pointer value | 
|  | 1741 |  | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 1742 | EmulateInstruction::Context context; | 
|  | 1743 | context.type = EmulateInstruction::eContextRegisterPlusOffset; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 1744 | RegisterInfo dwarf_reg; | 
|  | 1745 | GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, dwarf_reg); | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 1746 | context.SetRegisterPlusOffset (dwarf_reg, -sp_offset); | 
| Johnny Chen | 0d0148e | 2011-01-28 02:26:08 +0000 | [diff] [blame] | 1747 |  | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 1748 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r12, addr)) | 
| Johnny Chen | 0d0148e | 2011-01-28 02:26:08 +0000 | [diff] [blame] | 1749 | return false; | 
|  | 1750 | } | 
|  | 1751 | return true; | 
|  | 1752 | } | 
|  | 1753 |  | 
| Johnny Chen | c9e747f | 2011-02-23 01:55:07 +0000 | [diff] [blame] | 1754 | // This instruction subtracts an immediate value from the SP value, and writes | 
|  | 1755 | // the result to the destination register. | 
|  | 1756 | // | 
|  | 1757 | // If Rd == 13 => A sub operation to adjust the SP -- allocate space for local storage. | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 1758 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 1759 | EmulateInstructionARM::EmulateSUBSPImm (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | 4c0e0bc | 2011-01-25 22:45:28 +0000 | [diff] [blame] | 1760 | { | 
|  | 1761 | #if 0 | 
|  | 1762 | // ARM pseudo code... | 
|  | 1763 | if (ConditionPassed()) | 
|  | 1764 | { | 
|  | 1765 | EncodingSpecificOperations(); | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 1766 | (result, carry, overflow) = AddWithCarry(SP, NOT(imm32), '1'); | 
| Johnny Chen | 15a7a6b | 2011-02-23 23:47:56 +0000 | [diff] [blame] | 1767 | if d == 15 then        // Can only occur for ARM encoding | 
| Johnny Chen | 799dfd0 | 2011-01-26 23:14:33 +0000 | [diff] [blame] | 1768 | ALUWritePC(result); // setflags is always FALSE here | 
| Johnny Chen | 4c0e0bc | 2011-01-25 22:45:28 +0000 | [diff] [blame] | 1769 | else | 
|  | 1770 | R[d] = result; | 
|  | 1771 | if setflags then | 
|  | 1772 | APSR.N = result<31>; | 
|  | 1773 | APSR.Z = IsZeroBit(result); | 
|  | 1774 | APSR.C = carry; | 
|  | 1775 | APSR.V = overflow; | 
|  | 1776 | } | 
|  | 1777 | #endif | 
|  | 1778 |  | 
|  | 1779 | bool success = false; | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 1780 | if (ConditionPassed(opcode)) | 
| Johnny Chen | 4c0e0bc | 2011-01-25 22:45:28 +0000 | [diff] [blame] | 1781 | { | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 1782 | const addr_t sp = ReadCoreReg (SP_REG, &success); | 
| Johnny Chen | 4c0e0bc | 2011-01-25 22:45:28 +0000 | [diff] [blame] | 1783 | if (!success) | 
|  | 1784 | return false; | 
| Johnny Chen | c9e747f | 2011-02-23 01:55:07 +0000 | [diff] [blame] | 1785 |  | 
|  | 1786 | uint32_t Rd; | 
|  | 1787 | bool setflags; | 
| Johnny Chen | 4c0e0bc | 2011-01-25 22:45:28 +0000 | [diff] [blame] | 1788 | uint32_t imm32; | 
|  | 1789 | switch (encoding) { | 
| Johnny Chen | e445502 | 2011-01-26 00:08:59 +0000 | [diff] [blame] | 1790 | case eEncodingT1: | 
| Johnny Chen | c9e747f | 2011-02-23 01:55:07 +0000 | [diff] [blame] | 1791 | Rd = 13; | 
|  | 1792 | setflags = false; | 
| Johnny Chen | a695f95 | 2011-02-23 21:24:25 +0000 | [diff] [blame] | 1793 | imm32 = ThumbImm7Scaled(opcode); // imm32 = ZeroExtend(imm7:'00', 32) | 
| Johnny Chen | ed32e7c | 2011-02-22 23:42:58 +0000 | [diff] [blame] | 1794 | break; | 
| Johnny Chen | 60c0d62 | 2011-01-25 23:49:39 +0000 | [diff] [blame] | 1795 | case eEncodingT2: | 
| Johnny Chen | c9e747f | 2011-02-23 01:55:07 +0000 | [diff] [blame] | 1796 | Rd = Bits32(opcode, 11, 8); | 
|  | 1797 | setflags = BitIsSet(opcode, 20); | 
| Johnny Chen | 60c0d62 | 2011-01-25 23:49:39 +0000 | [diff] [blame] | 1798 | imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8) | 
| Johnny Chen | c9e747f | 2011-02-23 01:55:07 +0000 | [diff] [blame] | 1799 | if (Rd == 15 && setflags) | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 1800 | return EmulateCMPImm(opcode, eEncodingT2); | 
| Johnny Chen | c9e747f | 2011-02-23 01:55:07 +0000 | [diff] [blame] | 1801 | if (Rd == 15 && !setflags) | 
|  | 1802 | return false; | 
| Johnny Chen | 60c0d62 | 2011-01-25 23:49:39 +0000 | [diff] [blame] | 1803 | break; | 
|  | 1804 | case eEncodingT3: | 
| Johnny Chen | c9e747f | 2011-02-23 01:55:07 +0000 | [diff] [blame] | 1805 | Rd = Bits32(opcode, 11, 8); | 
|  | 1806 | setflags = false; | 
| Johnny Chen | 60c0d62 | 2011-01-25 23:49:39 +0000 | [diff] [blame] | 1807 | imm32 = ThumbImm12(opcode); // imm32 = ZeroExtend(i:imm3:imm8, 32) | 
| Johnny Chen | 15a7a6b | 2011-02-23 23:47:56 +0000 | [diff] [blame] | 1808 | if (Rd == 15) | 
|  | 1809 | return false; | 
| Johnny Chen | 60c0d62 | 2011-01-25 23:49:39 +0000 | [diff] [blame] | 1810 | break; | 
| Johnny Chen | 4c0e0bc | 2011-01-25 22:45:28 +0000 | [diff] [blame] | 1811 | case eEncodingA1: | 
| Johnny Chen | c9e747f | 2011-02-23 01:55:07 +0000 | [diff] [blame] | 1812 | Rd = Bits32(opcode, 15, 12); | 
|  | 1813 | setflags = BitIsSet(opcode, 20); | 
| Johnny Chen | 60c0d62 | 2011-01-25 23:49:39 +0000 | [diff] [blame] | 1814 | imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12) | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 1815 |  | 
| Johnny Chen | 15a7a6b | 2011-02-23 23:47:56 +0000 | [diff] [blame] | 1816 | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related instructions; | 
| Johnny Chen | 15a7a6b | 2011-02-23 23:47:56 +0000 | [diff] [blame] | 1817 | if (Rd == 15 && setflags) | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 1818 | return EmulateSUBSPcLrEtc (opcode, encoding); | 
| Johnny Chen | 4c0e0bc | 2011-01-25 22:45:28 +0000 | [diff] [blame] | 1819 | break; | 
|  | 1820 | default: | 
|  | 1821 | return false; | 
|  | 1822 | } | 
| Johnny Chen | c9e747f | 2011-02-23 01:55:07 +0000 | [diff] [blame] | 1823 | AddWithCarryResult res = AddWithCarry(sp, ~imm32, 1); | 
|  | 1824 |  | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 1825 | EmulateInstruction::Context context; | 
| Johnny Chen | c9e747f | 2011-02-23 01:55:07 +0000 | [diff] [blame] | 1826 | if (Rd == 13) | 
|  | 1827 | { | 
| Caroline Tice | 2b03ed8 | 2011-03-16 00:06:12 +0000 | [diff] [blame] | 1828 | uint64_t imm64 = imm32;  // Need to expand it to 64 bits before attempting to negate it, or the wrong | 
|  | 1829 | // value gets passed down to context.SetImmediateSigned. | 
| Johnny Chen | c9e747f | 2011-02-23 01:55:07 +0000 | [diff] [blame] | 1830 | context.type = EmulateInstruction::eContextAdjustStackPointer; | 
| Caroline Tice | 2b03ed8 | 2011-03-16 00:06:12 +0000 | [diff] [blame] | 1831 | context.SetImmediateSigned (-imm64); // the stack pointer offset | 
| Johnny Chen | c9e747f | 2011-02-23 01:55:07 +0000 | [diff] [blame] | 1832 | } | 
|  | 1833 | else | 
|  | 1834 | { | 
|  | 1835 | context.type = EmulateInstruction::eContextImmediate; | 
|  | 1836 | context.SetNoArgs (); | 
|  | 1837 | } | 
|  | 1838 |  | 
|  | 1839 | if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, res.carry_out, res.overflow)) | 
| Johnny Chen | 4c0e0bc | 2011-01-25 22:45:28 +0000 | [diff] [blame] | 1840 | return false; | 
|  | 1841 | } | 
|  | 1842 | return true; | 
|  | 1843 | } | 
|  | 1844 |  | 
| Johnny Chen | 08c25e8 | 2011-01-31 18:02:28 +0000 | [diff] [blame] | 1845 | // A store operation to the stack that also updates the SP. | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 1846 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 1847 | EmulateInstructionARM::EmulateSTRRtSP (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | ce1ca77 | 2011-01-25 01:13:00 +0000 | [diff] [blame] | 1848 | { | 
|  | 1849 | #if 0 | 
|  | 1850 | // ARM pseudo code... | 
|  | 1851 | if (ConditionPassed()) | 
|  | 1852 | { | 
|  | 1853 | EncodingSpecificOperations(); | 
|  | 1854 | offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | 1855 | address = if index then offset_addr else R[n]; | 
|  | 1856 | MemU[address,4] = if t == 15 then PCStoreValue() else R[t]; | 
|  | 1857 | if wback then R[n] = offset_addr; | 
|  | 1858 | } | 
|  | 1859 | #endif | 
|  | 1860 |  | 
| Greg Clayton | 107e53d | 2011-07-06 04:07:21 +0000 | [diff] [blame] | 1861 | bool conditional = false; | 
| Johnny Chen | ce1ca77 | 2011-01-25 01:13:00 +0000 | [diff] [blame] | 1862 | bool success = false; | 
| Greg Clayton | 107e53d | 2011-07-06 04:07:21 +0000 | [diff] [blame] | 1863 | if (ConditionPassed(opcode, &conditional)) | 
| Johnny Chen | ce1ca77 | 2011-01-25 01:13:00 +0000 | [diff] [blame] | 1864 | { | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 1865 | const uint32_t addr_byte_size = GetAddressByteSize(); | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 1866 | const addr_t sp = ReadCoreReg (SP_REG, &success); | 
| Johnny Chen | ce1ca77 | 2011-01-25 01:13:00 +0000 | [diff] [blame] | 1867 | if (!success) | 
|  | 1868 | return false; | 
| Johnny Chen | 91d9986 | 2011-01-25 19:07:04 +0000 | [diff] [blame] | 1869 | uint32_t Rt; // the source register | 
| Johnny Chen | ce1ca77 | 2011-01-25 01:13:00 +0000 | [diff] [blame] | 1870 | uint32_t imm12; | 
| Caroline Tice | 3e40797 | 2011-03-18 19:41:00 +0000 | [diff] [blame] | 1871 | uint32_t Rn;  // This function assumes Rn is the SP, but we should verify that. | 
|  | 1872 |  | 
|  | 1873 | bool index; | 
|  | 1874 | bool add; | 
|  | 1875 | bool wback; | 
| Johnny Chen | ce1ca77 | 2011-01-25 01:13:00 +0000 | [diff] [blame] | 1876 | switch (encoding) { | 
|  | 1877 | case eEncodingA1: | 
| Johnny Chen | 108d5aa | 2011-01-26 01:00:55 +0000 | [diff] [blame] | 1878 | Rt = Bits32(opcode, 15, 12); | 
|  | 1879 | imm12 = Bits32(opcode, 11, 0); | 
| Caroline Tice | 3e40797 | 2011-03-18 19:41:00 +0000 | [diff] [blame] | 1880 | Rn = Bits32 (opcode, 19, 16); | 
|  | 1881 |  | 
|  | 1882 | if (Rn != 13) // 13 is the SP reg on ARM.  Verify that Rn == SP. | 
|  | 1883 | return false; | 
|  | 1884 |  | 
|  | 1885 | index = BitIsSet (opcode, 24); | 
|  | 1886 | add = BitIsSet (opcode, 23); | 
|  | 1887 | wback = (BitIsClear (opcode, 24) || BitIsSet (opcode, 21)); | 
|  | 1888 |  | 
|  | 1889 | if (wback && ((Rn == 15) || (Rn == Rt))) | 
|  | 1890 | return false; | 
| Johnny Chen | ce1ca77 | 2011-01-25 01:13:00 +0000 | [diff] [blame] | 1891 | break; | 
|  | 1892 | default: | 
|  | 1893 | return false; | 
|  | 1894 | } | 
| Caroline Tice | 3e40797 | 2011-03-18 19:41:00 +0000 | [diff] [blame] | 1895 | addr_t offset_addr; | 
|  | 1896 | if (add) | 
|  | 1897 | offset_addr = sp + imm12; | 
|  | 1898 | else | 
|  | 1899 | offset_addr = sp - imm12; | 
|  | 1900 |  | 
|  | 1901 | addr_t addr; | 
|  | 1902 | if (index) | 
|  | 1903 | addr = offset_addr; | 
|  | 1904 | else | 
|  | 1905 | addr = sp; | 
| Johnny Chen | ce1ca77 | 2011-01-25 01:13:00 +0000 | [diff] [blame] | 1906 |  | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 1907 | EmulateInstruction::Context context; | 
| Greg Clayton | 107e53d | 2011-07-06 04:07:21 +0000 | [diff] [blame] | 1908 | if (conditional) | 
|  | 1909 | context.type = EmulateInstruction::eContextRegisterStore; | 
|  | 1910 | else | 
|  | 1911 | context.type = EmulateInstruction::eContextPushRegisterOnStack; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 1912 | RegisterInfo sp_reg; | 
| Greg Clayton | b9e8f6e | 2011-05-18 01:58:14 +0000 | [diff] [blame] | 1913 | RegisterInfo dwarf_reg; | 
|  | 1914 |  | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 1915 | GetRegisterInfo (eRegisterKindDWARF, dwarf_sp, sp_reg); | 
| Greg Clayton | b9e8f6e | 2011-05-18 01:58:14 +0000 | [diff] [blame] | 1916 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + Rt, dwarf_reg); | 
|  | 1917 | context.SetRegisterToRegisterPlusOffset ( dwarf_reg, sp_reg, addr - sp); | 
| Johnny Chen | 91d9986 | 2011-01-25 19:07:04 +0000 | [diff] [blame] | 1918 | if (Rt != 15) | 
| Johnny Chen | ce1ca77 | 2011-01-25 01:13:00 +0000 | [diff] [blame] | 1919 | { | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 1920 | uint32_t reg_value = ReadCoreReg(Rt, &success); | 
| Johnny Chen | ce1ca77 | 2011-01-25 01:13:00 +0000 | [diff] [blame] | 1921 | if (!success) | 
|  | 1922 | return false; | 
| Caroline Tice | cc96eb5 | 2011-02-17 19:20:40 +0000 | [diff] [blame] | 1923 | if (!MemUWrite (context, addr, reg_value, addr_byte_size)) | 
| Johnny Chen | ce1ca77 | 2011-01-25 01:13:00 +0000 | [diff] [blame] | 1924 | return false; | 
|  | 1925 | } | 
|  | 1926 | else | 
|  | 1927 | { | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 1928 | const uint32_t pc = ReadCoreReg(PC_REG, &success); | 
| Johnny Chen | ce1ca77 | 2011-01-25 01:13:00 +0000 | [diff] [blame] | 1929 | if (!success) | 
|  | 1930 | return false; | 
| Caroline Tice | 8d681f5 | 2011-03-17 23:50:16 +0000 | [diff] [blame] | 1931 | if (!MemUWrite (context, addr, pc, addr_byte_size)) | 
| Johnny Chen | ce1ca77 | 2011-01-25 01:13:00 +0000 | [diff] [blame] | 1932 | return false; | 
|  | 1933 | } | 
|  | 1934 |  | 
| Caroline Tice | 3e40797 | 2011-03-18 19:41:00 +0000 | [diff] [blame] | 1935 |  | 
|  | 1936 | if (wback) | 
|  | 1937 | { | 
|  | 1938 | context.type = EmulateInstruction::eContextAdjustStackPointer; | 
|  | 1939 | context.SetImmediateSigned (addr - sp); | 
|  | 1940 | if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, offset_addr)) | 
|  | 1941 | return false; | 
|  | 1942 | } | 
| Johnny Chen | ce1ca77 | 2011-01-25 01:13:00 +0000 | [diff] [blame] | 1943 | } | 
|  | 1944 | return true; | 
|  | 1945 | } | 
|  | 1946 |  | 
| Johnny Chen | 08c25e8 | 2011-01-31 18:02:28 +0000 | [diff] [blame] | 1947 | // Vector Push stores multiple extension registers to the stack. | 
|  | 1948 | // It also updates SP to point to the start of the stored data. | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 1949 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 1950 | EmulateInstructionARM::EmulateVPUSH (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | 799dfd0 | 2011-01-26 23:14:33 +0000 | [diff] [blame] | 1951 | { | 
|  | 1952 | #if 0 | 
|  | 1953 | // ARM pseudo code... | 
|  | 1954 | if (ConditionPassed()) | 
|  | 1955 | { | 
|  | 1956 | EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(13); | 
|  | 1957 | address = SP - imm32; | 
|  | 1958 | SP = SP - imm32; | 
|  | 1959 | if single_regs then | 
|  | 1960 | for r = 0 to regs-1 | 
|  | 1961 | MemA[address,4] = S[d+r]; address = address+4; | 
|  | 1962 | else | 
|  | 1963 | for r = 0 to regs-1 | 
|  | 1964 | // Store as two word-aligned words in the correct order for current endianness. | 
|  | 1965 | MemA[address,4] = if BigEndian() then D[d+r]<63:32> else D[d+r]<31:0>; | 
|  | 1966 | MemA[address+4,4] = if BigEndian() then D[d+r]<31:0> else D[d+r]<63:32>; | 
|  | 1967 | address = address+8; | 
|  | 1968 | } | 
|  | 1969 | #endif | 
|  | 1970 |  | 
|  | 1971 | bool success = false; | 
| Greg Clayton | 107e53d | 2011-07-06 04:07:21 +0000 | [diff] [blame] | 1972 | bool conditional = false; | 
|  | 1973 | if (ConditionPassed(opcode, &conditional)) | 
| Johnny Chen | 799dfd0 | 2011-01-26 23:14:33 +0000 | [diff] [blame] | 1974 | { | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 1975 | const uint32_t addr_byte_size = GetAddressByteSize(); | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 1976 | const addr_t sp = ReadCoreReg (SP_REG, &success); | 
| Johnny Chen | 799dfd0 | 2011-01-26 23:14:33 +0000 | [diff] [blame] | 1977 | if (!success) | 
|  | 1978 | return false; | 
|  | 1979 | bool single_regs; | 
| Johnny Chen | 587a0a4 | 2011-02-01 18:35:28 +0000 | [diff] [blame] | 1980 | uint32_t d;     // UInt(D:Vd) or UInt(Vd:D) starting register | 
| Johnny Chen | 799dfd0 | 2011-01-26 23:14:33 +0000 | [diff] [blame] | 1981 | uint32_t imm32; // stack offset | 
|  | 1982 | uint32_t regs;  // number of registers | 
|  | 1983 | switch (encoding) { | 
|  | 1984 | case eEncodingT1: | 
|  | 1985 | case eEncodingA1: | 
|  | 1986 | single_regs = false; | 
| Johnny Chen | bd59990 | 2011-02-10 21:39:01 +0000 | [diff] [blame] | 1987 | d = Bit32(opcode, 22) << 4 | Bits32(opcode, 15, 12); | 
| Johnny Chen | 799dfd0 | 2011-01-26 23:14:33 +0000 | [diff] [blame] | 1988 | imm32 = Bits32(opcode, 7, 0) * addr_byte_size; | 
|  | 1989 | // If UInt(imm8) is odd, see "FSTMX". | 
|  | 1990 | regs = Bits32(opcode, 7, 0) / 2; | 
|  | 1991 | // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE; | 
|  | 1992 | if (regs == 0 || regs > 16 || (d + regs) > 32) | 
|  | 1993 | return false; | 
|  | 1994 | break; | 
|  | 1995 | case eEncodingT2: | 
|  | 1996 | case eEncodingA2: | 
|  | 1997 | single_regs = true; | 
| Johnny Chen | bd59990 | 2011-02-10 21:39:01 +0000 | [diff] [blame] | 1998 | d = Bits32(opcode, 15, 12) << 1 | Bit32(opcode, 22); | 
| Johnny Chen | 799dfd0 | 2011-01-26 23:14:33 +0000 | [diff] [blame] | 1999 | imm32 = Bits32(opcode, 7, 0) * addr_byte_size; | 
|  | 2000 | regs = Bits32(opcode, 7, 0); | 
|  | 2001 | // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE; | 
|  | 2002 | if (regs == 0 || regs > 16 || (d + regs) > 32) | 
|  | 2003 | return false; | 
|  | 2004 | break; | 
|  | 2005 | default: | 
|  | 2006 | return false; | 
|  | 2007 | } | 
|  | 2008 | uint32_t start_reg = single_regs ? dwarf_s0 : dwarf_d0; | 
|  | 2009 | uint32_t reg_byte_size = single_regs ? addr_byte_size : addr_byte_size * 2; | 
|  | 2010 | addr_t sp_offset = imm32; | 
|  | 2011 | addr_t addr = sp - sp_offset; | 
|  | 2012 | uint32_t i; | 
|  | 2013 |  | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 2014 | EmulateInstruction::Context context; | 
| Greg Clayton | 107e53d | 2011-07-06 04:07:21 +0000 | [diff] [blame] | 2015 | if (conditional) | 
|  | 2016 | context.type = EmulateInstruction::eContextRegisterStore; | 
|  | 2017 | else | 
|  | 2018 | context.type = EmulateInstruction::eContextPushRegisterOnStack; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 2019 | RegisterInfo dwarf_reg; | 
|  | 2020 | RegisterInfo sp_reg; | 
|  | 2021 | GetRegisterInfo (eRegisterKindDWARF, dwarf_sp, sp_reg); | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 2022 | for (i=0; i<regs; ++i) | 
| Johnny Chen | 799dfd0 | 2011-01-26 23:14:33 +0000 | [diff] [blame] | 2023 | { | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 2024 | GetRegisterInfo (eRegisterKindDWARF, start_reg + d + i, dwarf_reg); | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 2025 | context.SetRegisterToRegisterPlusOffset ( dwarf_reg, sp_reg, addr - sp); | 
| Johnny Chen | 799dfd0 | 2011-01-26 23:14:33 +0000 | [diff] [blame] | 2026 | // uint64_t to accommodate 64-bit registers. | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 2027 | uint64_t reg_value = ReadRegisterUnsigned (&dwarf_reg, 0, &success); | 
| Johnny Chen | 799dfd0 | 2011-01-26 23:14:33 +0000 | [diff] [blame] | 2028 | if (!success) | 
|  | 2029 | return false; | 
| Caroline Tice | cc96eb5 | 2011-02-17 19:20:40 +0000 | [diff] [blame] | 2030 | if (!MemAWrite (context, addr, reg_value, reg_byte_size)) | 
| Johnny Chen | 799dfd0 | 2011-01-26 23:14:33 +0000 | [diff] [blame] | 2031 | return false; | 
|  | 2032 | addr += reg_byte_size; | 
|  | 2033 | } | 
|  | 2034 |  | 
|  | 2035 | context.type = EmulateInstruction::eContextAdjustStackPointer; | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 2036 | context.SetImmediateSigned (-sp_offset); | 
| Johnny Chen | 799dfd0 | 2011-01-26 23:14:33 +0000 | [diff] [blame] | 2037 |  | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 2038 | if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp - sp_offset)) | 
| Johnny Chen | 799dfd0 | 2011-01-26 23:14:33 +0000 | [diff] [blame] | 2039 | return false; | 
|  | 2040 | } | 
|  | 2041 | return true; | 
|  | 2042 | } | 
|  | 2043 |  | 
| Johnny Chen | 587a0a4 | 2011-02-01 18:35:28 +0000 | [diff] [blame] | 2044 | // Vector Pop loads multiple extension registers from the stack. | 
|  | 2045 | // It also updates SP to point just above the loaded data. | 
|  | 2046 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 2047 | EmulateInstructionARM::EmulateVPOP (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | 587a0a4 | 2011-02-01 18:35:28 +0000 | [diff] [blame] | 2048 | { | 
|  | 2049 | #if 0 | 
|  | 2050 | // ARM pseudo code... | 
|  | 2051 | if (ConditionPassed()) | 
|  | 2052 | { | 
|  | 2053 | EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(13); | 
|  | 2054 | address = SP; | 
|  | 2055 | SP = SP + imm32; | 
|  | 2056 | if single_regs then | 
|  | 2057 | for r = 0 to regs-1 | 
|  | 2058 | S[d+r] = MemA[address,4]; address = address+4; | 
|  | 2059 | else | 
|  | 2060 | for r = 0 to regs-1 | 
|  | 2061 | word1 = MemA[address,4]; word2 = MemA[address+4,4]; address = address+8; | 
|  | 2062 | // Combine the word-aligned words in the correct order for current endianness. | 
|  | 2063 | D[d+r] = if BigEndian() then word1:word2 else word2:word1; | 
|  | 2064 | } | 
|  | 2065 | #endif | 
|  | 2066 |  | 
|  | 2067 | bool success = false; | 
| Greg Clayton | 107e53d | 2011-07-06 04:07:21 +0000 | [diff] [blame] | 2068 | bool conditional = false; | 
|  | 2069 | if (ConditionPassed(opcode, &conditional)) | 
| Johnny Chen | 587a0a4 | 2011-02-01 18:35:28 +0000 | [diff] [blame] | 2070 | { | 
|  | 2071 | const uint32_t addr_byte_size = GetAddressByteSize(); | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 2072 | const addr_t sp = ReadCoreReg (SP_REG, &success); | 
| Johnny Chen | 587a0a4 | 2011-02-01 18:35:28 +0000 | [diff] [blame] | 2073 | if (!success) | 
|  | 2074 | return false; | 
|  | 2075 | bool single_regs; | 
|  | 2076 | uint32_t d;     // UInt(D:Vd) or UInt(Vd:D) starting register | 
|  | 2077 | uint32_t imm32; // stack offset | 
|  | 2078 | uint32_t regs;  // number of registers | 
|  | 2079 | switch (encoding) { | 
|  | 2080 | case eEncodingT1: | 
|  | 2081 | case eEncodingA1: | 
|  | 2082 | single_regs = false; | 
| Johnny Chen | bd59990 | 2011-02-10 21:39:01 +0000 | [diff] [blame] | 2083 | d = Bit32(opcode, 22) << 4 | Bits32(opcode, 15, 12); | 
| Johnny Chen | 587a0a4 | 2011-02-01 18:35:28 +0000 | [diff] [blame] | 2084 | imm32 = Bits32(opcode, 7, 0) * addr_byte_size; | 
|  | 2085 | // If UInt(imm8) is odd, see "FLDMX". | 
|  | 2086 | regs = Bits32(opcode, 7, 0) / 2; | 
|  | 2087 | // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE; | 
|  | 2088 | if (regs == 0 || regs > 16 || (d + regs) > 32) | 
|  | 2089 | return false; | 
|  | 2090 | break; | 
|  | 2091 | case eEncodingT2: | 
|  | 2092 | case eEncodingA2: | 
|  | 2093 | single_regs = true; | 
| Johnny Chen | bd59990 | 2011-02-10 21:39:01 +0000 | [diff] [blame] | 2094 | d = Bits32(opcode, 15, 12) << 1 | Bit32(opcode, 22); | 
| Johnny Chen | 587a0a4 | 2011-02-01 18:35:28 +0000 | [diff] [blame] | 2095 | imm32 = Bits32(opcode, 7, 0) * addr_byte_size; | 
|  | 2096 | regs = Bits32(opcode, 7, 0); | 
|  | 2097 | // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE; | 
|  | 2098 | if (regs == 0 || regs > 16 || (d + regs) > 32) | 
|  | 2099 | return false; | 
|  | 2100 | break; | 
|  | 2101 | default: | 
|  | 2102 | return false; | 
|  | 2103 | } | 
|  | 2104 | uint32_t start_reg = single_regs ? dwarf_s0 : dwarf_d0; | 
|  | 2105 | uint32_t reg_byte_size = single_regs ? addr_byte_size : addr_byte_size * 2; | 
|  | 2106 | addr_t sp_offset = imm32; | 
|  | 2107 | addr_t addr = sp; | 
|  | 2108 | uint32_t i; | 
|  | 2109 | uint64_t data; // uint64_t to accomodate 64-bit registers. | 
|  | 2110 |  | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 2111 | EmulateInstruction::Context context; | 
| Greg Clayton | 107e53d | 2011-07-06 04:07:21 +0000 | [diff] [blame] | 2112 | if (conditional) | 
|  | 2113 | context.type = EmulateInstruction::eContextRegisterLoad; | 
|  | 2114 | else | 
|  | 2115 | context.type = EmulateInstruction::eContextPopRegisterOffStack; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 2116 | RegisterInfo dwarf_reg; | 
|  | 2117 | RegisterInfo sp_reg; | 
|  | 2118 | GetRegisterInfo (eRegisterKindDWARF, dwarf_sp, sp_reg); | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 2119 | for (i=0; i<regs; ++i) | 
| Johnny Chen | 587a0a4 | 2011-02-01 18:35:28 +0000 | [diff] [blame] | 2120 | { | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 2121 | GetRegisterInfo (eRegisterKindDWARF, start_reg + d + i, dwarf_reg); | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 2122 | context.SetRegisterPlusOffset (sp_reg, addr - sp); | 
| Caroline Tice | cc96eb5 | 2011-02-17 19:20:40 +0000 | [diff] [blame] | 2123 | data = MemARead(context, addr, reg_byte_size, 0, &success); | 
| Johnny Chen | 587a0a4 | 2011-02-01 18:35:28 +0000 | [diff] [blame] | 2124 | if (!success) | 
|  | 2125 | return false; | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 2126 | if (!WriteRegisterUnsigned(context, &dwarf_reg, data)) | 
| Johnny Chen | 587a0a4 | 2011-02-01 18:35:28 +0000 | [diff] [blame] | 2127 | return false; | 
|  | 2128 | addr += reg_byte_size; | 
|  | 2129 | } | 
|  | 2130 |  | 
|  | 2131 | context.type = EmulateInstruction::eContextAdjustStackPointer; | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 2132 | context.SetImmediateSigned (sp_offset); | 
| Johnny Chen | 587a0a4 | 2011-02-01 18:35:28 +0000 | [diff] [blame] | 2133 |  | 
|  | 2134 | if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp + sp_offset)) | 
|  | 2135 | return false; | 
|  | 2136 | } | 
|  | 2137 | return true; | 
|  | 2138 | } | 
|  | 2139 |  | 
| Johnny Chen | b77be41 | 2011-02-04 00:40:18 +0000 | [diff] [blame] | 2140 | // SVC (previously SWI) | 
|  | 2141 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 2142 | EmulateInstructionARM::EmulateSVC (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | b77be41 | 2011-02-04 00:40:18 +0000 | [diff] [blame] | 2143 | { | 
|  | 2144 | #if 0 | 
|  | 2145 | // ARM pseudo code... | 
|  | 2146 | if (ConditionPassed()) | 
|  | 2147 | { | 
|  | 2148 | EncodingSpecificOperations(); | 
|  | 2149 | CallSupervisor(); | 
|  | 2150 | } | 
|  | 2151 | #endif | 
|  | 2152 |  | 
|  | 2153 | bool success = false; | 
| Johnny Chen | b77be41 | 2011-02-04 00:40:18 +0000 | [diff] [blame] | 2154 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 2155 | if (ConditionPassed(opcode)) | 
| Johnny Chen | b77be41 | 2011-02-04 00:40:18 +0000 | [diff] [blame] | 2156 | { | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 2157 | const uint32_t pc = ReadCoreReg(PC_REG, &success); | 
| Johnny Chen | b77be41 | 2011-02-04 00:40:18 +0000 | [diff] [blame] | 2158 | addr_t lr; // next instruction address | 
|  | 2159 | if (!success) | 
|  | 2160 | return false; | 
|  | 2161 | uint32_t imm32; // the immediate constant | 
|  | 2162 | uint32_t mode;  // ARM or Thumb mode | 
|  | 2163 | switch (encoding) { | 
|  | 2164 | case eEncodingT1: | 
|  | 2165 | lr = (pc + 2) | 1u; // return address | 
|  | 2166 | imm32 = Bits32(opcode, 7, 0); | 
|  | 2167 | mode = eModeThumb; | 
|  | 2168 | break; | 
|  | 2169 | case eEncodingA1: | 
|  | 2170 | lr = pc + 4; // return address | 
|  | 2171 | imm32 = Bits32(opcode, 23, 0); | 
|  | 2172 | mode = eModeARM; | 
|  | 2173 | break; | 
|  | 2174 | default: | 
|  | 2175 | return false; | 
|  | 2176 | } | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 2177 |  | 
|  | 2178 | EmulateInstruction::Context context; | 
|  | 2179 | context.type = EmulateInstruction::eContextSupervisorCall; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 2180 | context.SetISAAndImmediate (mode, imm32); | 
| Johnny Chen | b77be41 | 2011-02-04 00:40:18 +0000 | [diff] [blame] | 2181 | if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, lr)) | 
|  | 2182 | return false; | 
|  | 2183 | } | 
|  | 2184 | return true; | 
|  | 2185 | } | 
|  | 2186 |  | 
| Johnny Chen | c315f86 | 2011-02-05 00:46:10 +0000 | [diff] [blame] | 2187 | // If Then makes up to four following instructions (the IT block) conditional. | 
|  | 2188 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 2189 | EmulateInstructionARM::EmulateIT (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | c315f86 | 2011-02-05 00:46:10 +0000 | [diff] [blame] | 2190 | { | 
|  | 2191 | #if 0 | 
|  | 2192 | // ARM pseudo code... | 
|  | 2193 | EncodingSpecificOperations(); | 
|  | 2194 | ITSTATE.IT<7:0> = firstcond:mask; | 
|  | 2195 | #endif | 
|  | 2196 |  | 
| Johnny Chen | c315f86 | 2011-02-05 00:46:10 +0000 | [diff] [blame] | 2197 | m_it_session.InitIT(Bits32(opcode, 7, 0)); | 
|  | 2198 | return true; | 
|  | 2199 | } | 
|  | 2200 |  | 
| Greg Clayton | 04d397c | 2011-05-23 18:04:09 +0000 | [diff] [blame] | 2201 | bool | 
|  | 2202 | EmulateInstructionARM::EmulateNop (const uint32_t opcode, const ARMEncoding encoding) | 
|  | 2203 | { | 
|  | 2204 | // NOP, nothing to do... | 
|  | 2205 | return true; | 
|  | 2206 | } | 
|  | 2207 |  | 
| Johnny Chen | 3b620b3 | 2011-02-07 20:11:47 +0000 | [diff] [blame] | 2208 | // Branch causes a branch to a target address. | 
|  | 2209 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 2210 | EmulateInstructionARM::EmulateB (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | 3b620b3 | 2011-02-07 20:11:47 +0000 | [diff] [blame] | 2211 | { | 
|  | 2212 | #if 0 | 
|  | 2213 | // ARM pseudo code... | 
|  | 2214 | if (ConditionPassed()) | 
|  | 2215 | { | 
|  | 2216 | EncodingSpecificOperations(); | 
|  | 2217 | BranchWritePC(PC + imm32); | 
|  | 2218 | } | 
|  | 2219 | #endif | 
|  | 2220 |  | 
|  | 2221 | bool success = false; | 
| Johnny Chen | 3b620b3 | 2011-02-07 20:11:47 +0000 | [diff] [blame] | 2222 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 2223 | if (ConditionPassed(opcode)) | 
| Johnny Chen | 9ee056b | 2011-02-08 00:06:35 +0000 | [diff] [blame] | 2224 | { | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 2225 | EmulateInstruction::Context context; | 
|  | 2226 | context.type = EmulateInstruction::eContextRelativeBranchImmediate; | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 2227 | const uint32_t pc = ReadCoreReg(PC_REG, &success); | 
| Johnny Chen | 9ee056b | 2011-02-08 00:06:35 +0000 | [diff] [blame] | 2228 | if (!success) | 
|  | 2229 | return false; | 
| Johnny Chen | 53ebab7 | 2011-02-08 23:21:57 +0000 | [diff] [blame] | 2230 | addr_t target; // target address | 
| Johnny Chen | 9ee056b | 2011-02-08 00:06:35 +0000 | [diff] [blame] | 2231 | int32_t imm32; // PC-relative offset | 
|  | 2232 | switch (encoding) { | 
|  | 2233 | case eEncodingT1: | 
|  | 2234 | // The 'cond' field is handled in EmulateInstructionARM::CurrentCond(). | 
|  | 2235 | imm32 = llvm::SignExtend32<9>(Bits32(opcode, 7, 0) << 1); | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 2236 | target = pc + imm32; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 2237 | context.SetISAAndImmediateSigned (eModeThumb, 4 + imm32); | 
| Johnny Chen | 9ee056b | 2011-02-08 00:06:35 +0000 | [diff] [blame] | 2238 | break; | 
|  | 2239 | case eEncodingT2: | 
|  | 2240 | imm32 = llvm::SignExtend32<12>(Bits32(opcode, 10, 0)); | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 2241 | target = pc + imm32; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 2242 | context.SetISAAndImmediateSigned (eModeThumb, 4 + imm32); | 
| Johnny Chen | 9ee056b | 2011-02-08 00:06:35 +0000 | [diff] [blame] | 2243 | break; | 
|  | 2244 | case eEncodingT3: | 
|  | 2245 | // The 'cond' field is handled in EmulateInstructionARM::CurrentCond(). | 
|  | 2246 | { | 
| Johnny Chen | bd59990 | 2011-02-10 21:39:01 +0000 | [diff] [blame] | 2247 | uint32_t S = Bit32(opcode, 26); | 
| Johnny Chen | 9ee056b | 2011-02-08 00:06:35 +0000 | [diff] [blame] | 2248 | uint32_t imm6 = Bits32(opcode, 21, 16); | 
| Johnny Chen | bd59990 | 2011-02-10 21:39:01 +0000 | [diff] [blame] | 2249 | uint32_t J1 = Bit32(opcode, 13); | 
|  | 2250 | uint32_t J2 = Bit32(opcode, 11); | 
| Johnny Chen | 9ee056b | 2011-02-08 00:06:35 +0000 | [diff] [blame] | 2251 | uint32_t imm11 = Bits32(opcode, 10, 0); | 
| Johnny Chen | 53ebab7 | 2011-02-08 23:21:57 +0000 | [diff] [blame] | 2252 | uint32_t imm21 = (S << 20) | (J2 << 19) | (J1 << 18) | (imm6 << 12) | (imm11 << 1); | 
| Johnny Chen | 9ee056b | 2011-02-08 00:06:35 +0000 | [diff] [blame] | 2253 | imm32 = llvm::SignExtend32<21>(imm21); | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 2254 | target = pc + imm32; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 2255 | context.SetISAAndImmediateSigned (eModeThumb, 4 + imm32); | 
| Johnny Chen | 9ee056b | 2011-02-08 00:06:35 +0000 | [diff] [blame] | 2256 | break; | 
|  | 2257 | } | 
|  | 2258 | case eEncodingT4: | 
|  | 2259 | { | 
| Johnny Chen | bd59990 | 2011-02-10 21:39:01 +0000 | [diff] [blame] | 2260 | uint32_t S = Bit32(opcode, 26); | 
| Johnny Chen | 9ee056b | 2011-02-08 00:06:35 +0000 | [diff] [blame] | 2261 | uint32_t imm10 = Bits32(opcode, 25, 16); | 
| Johnny Chen | bd59990 | 2011-02-10 21:39:01 +0000 | [diff] [blame] | 2262 | uint32_t J1 = Bit32(opcode, 13); | 
|  | 2263 | uint32_t J2 = Bit32(opcode, 11); | 
| Johnny Chen | 9ee056b | 2011-02-08 00:06:35 +0000 | [diff] [blame] | 2264 | uint32_t imm11 = Bits32(opcode, 10, 0); | 
|  | 2265 | uint32_t I1 = !(J1 ^ S); | 
|  | 2266 | uint32_t I2 = !(J2 ^ S); | 
| Johnny Chen | 53ebab7 | 2011-02-08 23:21:57 +0000 | [diff] [blame] | 2267 | uint32_t imm25 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1); | 
| Johnny Chen | 9ee056b | 2011-02-08 00:06:35 +0000 | [diff] [blame] | 2268 | imm32 = llvm::SignExtend32<25>(imm25); | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 2269 | target = pc + imm32; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 2270 | context.SetISAAndImmediateSigned (eModeThumb, 4 + imm32); | 
| Johnny Chen | 9ee056b | 2011-02-08 00:06:35 +0000 | [diff] [blame] | 2271 | break; | 
|  | 2272 | } | 
|  | 2273 | case eEncodingA1: | 
|  | 2274 | imm32 = llvm::SignExtend32<26>(Bits32(opcode, 23, 0) << 2); | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 2275 | target = pc + imm32; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 2276 | context.SetISAAndImmediateSigned (eModeARM, 8 + imm32); | 
| Johnny Chen | 9ee056b | 2011-02-08 00:06:35 +0000 | [diff] [blame] | 2277 | break; | 
|  | 2278 | default: | 
|  | 2279 | return false; | 
|  | 2280 | } | 
|  | 2281 | if (!BranchWritePC(context, target)) | 
|  | 2282 | return false; | 
|  | 2283 | } | 
|  | 2284 | return true; | 
| Johnny Chen | 3b620b3 | 2011-02-07 20:11:47 +0000 | [diff] [blame] | 2285 | } | 
|  | 2286 |  | 
| Johnny Chen | 53ebab7 | 2011-02-08 23:21:57 +0000 | [diff] [blame] | 2287 | // Compare and Branch on Nonzero and Compare and Branch on Zero compare the value in a register with | 
|  | 2288 | // zero and conditionally branch forward a constant value.  They do not affect the condition flags. | 
|  | 2289 | // CBNZ, CBZ | 
|  | 2290 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 2291 | EmulateInstructionARM::EmulateCB (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | 53ebab7 | 2011-02-08 23:21:57 +0000 | [diff] [blame] | 2292 | { | 
|  | 2293 | #if 0 | 
|  | 2294 | // ARM pseudo code... | 
|  | 2295 | EncodingSpecificOperations(); | 
|  | 2296 | if nonzero ^ IsZero(R[n]) then | 
|  | 2297 | BranchWritePC(PC + imm32); | 
|  | 2298 | #endif | 
|  | 2299 |  | 
|  | 2300 | bool success = false; | 
| Johnny Chen | 53ebab7 | 2011-02-08 23:21:57 +0000 | [diff] [blame] | 2301 |  | 
|  | 2302 | // Read the register value from the operand register Rn. | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 2303 | uint32_t reg_val = ReadCoreReg(Bits32(opcode, 2, 0), &success); | 
| Johnny Chen | 53ebab7 | 2011-02-08 23:21:57 +0000 | [diff] [blame] | 2304 | if (!success) | 
|  | 2305 | return false; | 
|  | 2306 |  | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 2307 | EmulateInstruction::Context context; | 
|  | 2308 | context.type = EmulateInstruction::eContextRelativeBranchImmediate; | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 2309 | const uint32_t pc = ReadCoreReg(PC_REG, &success); | 
| Johnny Chen | 53ebab7 | 2011-02-08 23:21:57 +0000 | [diff] [blame] | 2310 | if (!success) | 
|  | 2311 | return false; | 
|  | 2312 |  | 
|  | 2313 | addr_t target;  // target address | 
|  | 2314 | uint32_t imm32; // PC-relative offset to branch forward | 
|  | 2315 | bool nonzero; | 
|  | 2316 | switch (encoding) { | 
|  | 2317 | case eEncodingT1: | 
| Johnny Chen | bd59990 | 2011-02-10 21:39:01 +0000 | [diff] [blame] | 2318 | imm32 = Bit32(opcode, 9) << 6 | Bits32(opcode, 7, 3) << 1; | 
| Johnny Chen | 53ebab7 | 2011-02-08 23:21:57 +0000 | [diff] [blame] | 2319 | nonzero = BitIsSet(opcode, 11); | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 2320 | target = pc + imm32; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 2321 | context.SetISAAndImmediateSigned (eModeThumb, 4 + imm32); | 
| Johnny Chen | 53ebab7 | 2011-02-08 23:21:57 +0000 | [diff] [blame] | 2322 | break; | 
|  | 2323 | default: | 
|  | 2324 | return false; | 
|  | 2325 | } | 
|  | 2326 | if (nonzero ^ (reg_val == 0)) | 
|  | 2327 | if (!BranchWritePC(context, target)) | 
|  | 2328 | return false; | 
|  | 2329 |  | 
|  | 2330 | return true; | 
|  | 2331 | } | 
|  | 2332 |  | 
| Johnny Chen | 60299ec | 2011-02-17 19:34:27 +0000 | [diff] [blame] | 2333 | // Table Branch Byte causes a PC-relative forward branch using a table of single byte offsets. | 
|  | 2334 | // A base register provides a pointer to the table, and a second register supplies an index into the table. | 
|  | 2335 | // The branch length is twice the value of the byte returned from the table. | 
|  | 2336 | // | 
|  | 2337 | // Table Branch Halfword causes a PC-relative forward branch using a table of single halfword offsets. | 
|  | 2338 | // A base register provides a pointer to the table, and a second register supplies an index into the table. | 
|  | 2339 | // The branch length is twice the value of the halfword returned from the table. | 
|  | 2340 | // TBB, TBH | 
|  | 2341 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 2342 | EmulateInstructionARM::EmulateTB (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | 60299ec | 2011-02-17 19:34:27 +0000 | [diff] [blame] | 2343 | { | 
|  | 2344 | #if 0 | 
|  | 2345 | // ARM pseudo code... | 
|  | 2346 | EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | 2347 | if is_tbh then | 
|  | 2348 | halfwords = UInt(MemU[R[n]+LSL(R[m],1), 2]); | 
|  | 2349 | else | 
|  | 2350 | halfwords = UInt(MemU[R[n]+R[m], 1]); | 
|  | 2351 | BranchWritePC(PC + 2*halfwords); | 
|  | 2352 | #endif | 
|  | 2353 |  | 
|  | 2354 | bool success = false; | 
| Johnny Chen | 60299ec | 2011-02-17 19:34:27 +0000 | [diff] [blame] | 2355 |  | 
|  | 2356 | uint32_t Rn;     // the base register which contains the address of the table of branch lengths | 
|  | 2357 | uint32_t Rm;     // the index register which contains an integer pointing to a byte/halfword in the table | 
|  | 2358 | bool is_tbh;     // true if table branch halfword | 
|  | 2359 | switch (encoding) { | 
|  | 2360 | case eEncodingT1: | 
|  | 2361 | Rn = Bits32(opcode, 19, 16); | 
|  | 2362 | Rm = Bits32(opcode, 3, 0); | 
|  | 2363 | is_tbh = BitIsSet(opcode, 4); | 
|  | 2364 | if (Rn == 13 || BadReg(Rm)) | 
|  | 2365 | return false; | 
|  | 2366 | if (InITBlock() && !LastInITBlock()) | 
|  | 2367 | return false; | 
|  | 2368 | break; | 
|  | 2369 | default: | 
|  | 2370 | return false; | 
|  | 2371 | } | 
|  | 2372 |  | 
|  | 2373 | // Read the address of the table from the operand register Rn. | 
|  | 2374 | // The PC can be used, in which case the table immediately follows this instruction. | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 2375 | uint32_t base = ReadCoreReg(Rm, &success); | 
| Johnny Chen | 60299ec | 2011-02-17 19:34:27 +0000 | [diff] [blame] | 2376 | if (!success) | 
|  | 2377 | return false; | 
|  | 2378 |  | 
|  | 2379 | // the table index | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 2380 | uint32_t index = ReadCoreReg(Rm, &success); | 
| Johnny Chen | 60299ec | 2011-02-17 19:34:27 +0000 | [diff] [blame] | 2381 | if (!success) | 
|  | 2382 | return false; | 
|  | 2383 |  | 
|  | 2384 | // the offsetted table address | 
|  | 2385 | addr_t addr = base + (is_tbh ? index*2 : index); | 
|  | 2386 |  | 
|  | 2387 | // PC-relative offset to branch forward | 
|  | 2388 | EmulateInstruction::Context context; | 
|  | 2389 | context.type = EmulateInstruction::eContextTableBranchReadMemory; | 
| Johnny Chen | 104c8b6 | 2011-02-17 23:27:44 +0000 | [diff] [blame] | 2390 | uint32_t offset = MemURead(context, addr, is_tbh ? 2 : 1, 0, &success) * 2; | 
| Johnny Chen | 60299ec | 2011-02-17 19:34:27 +0000 | [diff] [blame] | 2391 | if (!success) | 
|  | 2392 | return false; | 
|  | 2393 |  | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 2394 | const uint32_t pc = ReadCoreReg(PC_REG, &success); | 
| Johnny Chen | 60299ec | 2011-02-17 19:34:27 +0000 | [diff] [blame] | 2395 | if (!success) | 
|  | 2396 | return false; | 
|  | 2397 |  | 
|  | 2398 | // target address | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 2399 | addr_t target = pc + offset; | 
| Johnny Chen | 60299ec | 2011-02-17 19:34:27 +0000 | [diff] [blame] | 2400 | context.type = EmulateInstruction::eContextRelativeBranchImmediate; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 2401 | context.SetISAAndImmediateSigned (eModeThumb, 4 + offset); | 
| Johnny Chen | 60299ec | 2011-02-17 19:34:27 +0000 | [diff] [blame] | 2402 |  | 
|  | 2403 | if (!BranchWritePC(context, target)) | 
|  | 2404 | return false; | 
|  | 2405 |  | 
|  | 2406 | return true; | 
|  | 2407 | } | 
|  | 2408 |  | 
| Caroline Tice | dcc11b3 | 2011-03-02 23:57:02 +0000 | [diff] [blame] | 2409 | // This instruction adds an immediate value to a register value, and writes the result to the destination register. | 
|  | 2410 | // It can optionally update the condition flags based on the result. | 
|  | 2411 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 2412 | EmulateInstructionARM::EmulateADDImmThumb (const uint32_t opcode, const ARMEncoding encoding) | 
| Caroline Tice | dcc11b3 | 2011-03-02 23:57:02 +0000 | [diff] [blame] | 2413 | { | 
|  | 2414 | #if 0 | 
|  | 2415 | if ConditionPassed() then | 
|  | 2416 | EncodingSpecificOperations(); | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 2417 | (result, carry, overflow) = AddWithCarry(R[n], imm32, '0'); | 
| Caroline Tice | dcc11b3 | 2011-03-02 23:57:02 +0000 | [diff] [blame] | 2418 | R[d] = result; | 
|  | 2419 | if setflags then | 
|  | 2420 | APSR.N = result<31>; | 
|  | 2421 | APSR.Z = IsZeroBit(result); | 
|  | 2422 | APSR.C = carry; | 
|  | 2423 | APSR.V = overflow; | 
|  | 2424 | #endif | 
|  | 2425 |  | 
|  | 2426 | bool success = false; | 
| Caroline Tice | dcc11b3 | 2011-03-02 23:57:02 +0000 | [diff] [blame] | 2427 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 2428 | if (ConditionPassed(opcode)) | 
| Caroline Tice | dcc11b3 | 2011-03-02 23:57:02 +0000 | [diff] [blame] | 2429 | { | 
|  | 2430 | uint32_t d; | 
|  | 2431 | uint32_t n; | 
|  | 2432 | bool setflags; | 
|  | 2433 | uint32_t imm32; | 
|  | 2434 | uint32_t carry_out; | 
|  | 2435 |  | 
|  | 2436 | //EncodingSpecificOperations(); | 
|  | 2437 | switch (encoding) | 
|  | 2438 | { | 
|  | 2439 | case eEncodingT1: | 
|  | 2440 | // d = UInt(Rd); n = UInt(Rn); setflags = !InITBlock(); imm32 = ZeroExtend(imm3, 32); | 
|  | 2441 | d = Bits32 (opcode, 2, 0); | 
|  | 2442 | n = Bits32 (opcode, 5, 3); | 
|  | 2443 | setflags = !InITBlock(); | 
|  | 2444 | imm32 = Bits32 (opcode, 8,6); | 
|  | 2445 |  | 
|  | 2446 | break; | 
|  | 2447 |  | 
|  | 2448 | case eEncodingT2: | 
|  | 2449 | // d = UInt(Rdn); n = UInt(Rdn); setflags = !InITBlock(); imm32 = ZeroExtend(imm8, 32); | 
|  | 2450 | d = Bits32 (opcode, 10, 8); | 
|  | 2451 | n = Bits32 (opcode, 10, 8); | 
|  | 2452 | setflags = !InITBlock(); | 
|  | 2453 | imm32 = Bits32 (opcode, 7, 0); | 
|  | 2454 |  | 
|  | 2455 | break; | 
|  | 2456 |  | 
|  | 2457 | case eEncodingT3: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 2458 | // if Rd == '1111' && S == '1' then SEE CMN (immediate); | 
|  | 2459 | // if Rn == '1101' then SEE ADD (SP plus immediate); | 
|  | 2460 | // d = UInt(Rd); n = UInt(Rn); setflags = (S == '1'); imm32 = ThumbExpandImm(i:imm3:imm8); | 
| Caroline Tice | dcc11b3 | 2011-03-02 23:57:02 +0000 | [diff] [blame] | 2461 | d = Bits32 (opcode, 11, 8); | 
|  | 2462 | n = Bits32 (opcode, 19, 16); | 
|  | 2463 | setflags = BitIsSet (opcode, 20); | 
|  | 2464 | imm32 = ThumbExpandImm_C (opcode, APSR_C, carry_out); | 
|  | 2465 |  | 
|  | 2466 | // if BadReg(d) || n == 15 then UNPREDICTABLE; | 
|  | 2467 | if (BadReg (d) || (n == 15)) | 
|  | 2468 | return false; | 
|  | 2469 |  | 
|  | 2470 | break; | 
|  | 2471 |  | 
|  | 2472 | case eEncodingT4: | 
|  | 2473 | { | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 2474 | // if Rn == '1111' then SEE ADR; | 
|  | 2475 | // if Rn == '1101' then SEE ADD (SP plus immediate); | 
| Caroline Tice | dcc11b3 | 2011-03-02 23:57:02 +0000 | [diff] [blame] | 2476 | // d = UInt(Rd); n = UInt(Rn); setflags = FALSE; imm32 = ZeroExtend(i:imm3:imm8, 32); | 
|  | 2477 | d = Bits32 (opcode, 11, 8); | 
|  | 2478 | n = Bits32 (opcode, 19, 16); | 
|  | 2479 | setflags = false; | 
|  | 2480 | uint32_t i = Bit32 (opcode, 26); | 
|  | 2481 | uint32_t imm3 = Bits32 (opcode, 14, 12); | 
|  | 2482 | uint32_t imm8 = Bits32 (opcode, 7, 0); | 
|  | 2483 | imm32 = (i << 11) | (imm3 << 8) | imm8; | 
|  | 2484 |  | 
|  | 2485 | // if BadReg(d) then UNPREDICTABLE; | 
|  | 2486 | if (BadReg (d)) | 
|  | 2487 | return false; | 
|  | 2488 |  | 
|  | 2489 | break; | 
|  | 2490 | } | 
|  | 2491 | default: | 
|  | 2492 | return false; | 
|  | 2493 | } | 
|  | 2494 |  | 
|  | 2495 | uint64_t Rn = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success); | 
|  | 2496 | if (!success) | 
|  | 2497 | return false; | 
|  | 2498 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 2499 | //(result, carry, overflow) = AddWithCarry(R[n], imm32, '0'); | 
| Caroline Tice | dcc11b3 | 2011-03-02 23:57:02 +0000 | [diff] [blame] | 2500 | AddWithCarryResult res = AddWithCarry (Rn, imm32, 0); | 
|  | 2501 |  | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 2502 | RegisterInfo reg_n; | 
|  | 2503 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, reg_n); | 
| Caroline Tice | dcc11b3 | 2011-03-02 23:57:02 +0000 | [diff] [blame] | 2504 |  | 
|  | 2505 | EmulateInstruction::Context context; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 2506 | context.type = eContextArithmetic; | 
| Caroline Tice | dcc11b3 | 2011-03-02 23:57:02 +0000 | [diff] [blame] | 2507 | context.SetRegisterPlusOffset (reg_n, imm32); | 
|  | 2508 |  | 
|  | 2509 | //R[d] = result; | 
|  | 2510 | //if setflags then | 
|  | 2511 | //APSR.N = result<31>; | 
|  | 2512 | //APSR.Z = IsZeroBit(result); | 
|  | 2513 | //APSR.C = carry; | 
|  | 2514 | //APSR.V = overflow; | 
|  | 2515 | if (!WriteCoreRegOptionalFlags (context, res.result, d, setflags, res.carry_out, res.overflow)) | 
|  | 2516 | return false; | 
|  | 2517 |  | 
|  | 2518 | } | 
|  | 2519 | return true; | 
|  | 2520 | } | 
|  | 2521 |  | 
| Johnny Chen | 8fa2059 | 2011-02-18 01:22:22 +0000 | [diff] [blame] | 2522 | // This instruction adds an immediate value to a register value, and writes the result to the destination | 
|  | 2523 | // register.  It can optionally update the condition flags based on the result. | 
|  | 2524 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 2525 | EmulateInstructionARM::EmulateADDImmARM (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | 8fa2059 | 2011-02-18 01:22:22 +0000 | [diff] [blame] | 2526 | { | 
|  | 2527 | #if 0 | 
|  | 2528 | // ARM pseudo code... | 
|  | 2529 | if ConditionPassed() then | 
|  | 2530 | EncodingSpecificOperations(); | 
|  | 2531 | (result, carry, overflow) = AddWithCarry(R[n], imm32, '0'); | 
|  | 2532 | if d == 15 then | 
|  | 2533 | ALUWritePC(result); // setflags is always FALSE here | 
|  | 2534 | else | 
|  | 2535 | R[d] = result; | 
|  | 2536 | if setflags then | 
|  | 2537 | APSR.N = result<31>; | 
|  | 2538 | APSR.Z = IsZeroBit(result); | 
|  | 2539 | APSR.C = carry; | 
|  | 2540 | APSR.V = overflow; | 
|  | 2541 | #endif | 
|  | 2542 |  | 
|  | 2543 | bool success = false; | 
| Johnny Chen | 8fa2059 | 2011-02-18 01:22:22 +0000 | [diff] [blame] | 2544 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 2545 | if (ConditionPassed(opcode)) | 
| Johnny Chen | 8fa2059 | 2011-02-18 01:22:22 +0000 | [diff] [blame] | 2546 | { | 
|  | 2547 | uint32_t Rd, Rn; | 
|  | 2548 | uint32_t imm32; // the immediate value to be added to the value obtained from Rn | 
|  | 2549 | bool setflags; | 
|  | 2550 | switch (encoding) | 
|  | 2551 | { | 
|  | 2552 | case eEncodingA1: | 
|  | 2553 | Rd = Bits32(opcode, 15, 12); | 
|  | 2554 | Rn = Bits32(opcode, 19, 16); | 
|  | 2555 | setflags = BitIsSet(opcode, 20); | 
|  | 2556 | imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12) | 
|  | 2557 | break; | 
|  | 2558 | default: | 
|  | 2559 | return false; | 
|  | 2560 | } | 
|  | 2561 |  | 
| Johnny Chen | 8fa2059 | 2011-02-18 01:22:22 +0000 | [diff] [blame] | 2562 | // Read the first operand. | 
| Johnny Chen | 157b959 | 2011-02-18 21:13:05 +0000 | [diff] [blame] | 2563 | uint32_t val1 = ReadCoreReg(Rn, &success); | 
| Johnny Chen | 8fa2059 | 2011-02-18 01:22:22 +0000 | [diff] [blame] | 2564 | if (!success) | 
|  | 2565 | return false; | 
|  | 2566 |  | 
|  | 2567 | AddWithCarryResult res = AddWithCarry(val1, imm32, 0); | 
|  | 2568 |  | 
|  | 2569 | EmulateInstruction::Context context; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 2570 | context.type = eContextArithmetic; | 
|  | 2571 | RegisterInfo dwarf_reg; | 
|  | 2572 | GetRegisterInfo (eRegisterKindDWARF, Rn, dwarf_reg); | 
| Caroline Tice | 080bf61 | 2011-04-05 18:46:00 +0000 | [diff] [blame] | 2573 | context.SetRegisterPlusOffset (dwarf_reg, imm32); | 
| Johnny Chen | 8fa2059 | 2011-02-18 01:22:22 +0000 | [diff] [blame] | 2574 |  | 
|  | 2575 | if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, res.carry_out, res.overflow)) | 
|  | 2576 | return false; | 
|  | 2577 | } | 
|  | 2578 | return true; | 
|  | 2579 | } | 
|  | 2580 |  | 
| Johnny Chen | d761dcf | 2011-02-17 22:03:29 +0000 | [diff] [blame] | 2581 | // This instruction adds a register value and an optionally-shifted register value, and writes the result | 
|  | 2582 | // to the destination register. It can optionally update the condition flags based on the result. | 
| Johnny Chen | 26863dc | 2011-02-09 23:43:29 +0000 | [diff] [blame] | 2583 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 2584 | EmulateInstructionARM::EmulateADDReg (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | 26863dc | 2011-02-09 23:43:29 +0000 | [diff] [blame] | 2585 | { | 
|  | 2586 | #if 0 | 
|  | 2587 | // ARM pseudo code... | 
|  | 2588 | if ConditionPassed() then | 
|  | 2589 | EncodingSpecificOperations(); | 
|  | 2590 | shifted = Shift(R[m], shift_t, shift_n, APSR.C); | 
|  | 2591 | (result, carry, overflow) = AddWithCarry(R[n], shifted, '0'); | 
|  | 2592 | if d == 15 then | 
|  | 2593 | ALUWritePC(result); // setflags is always FALSE here | 
|  | 2594 | else | 
|  | 2595 | R[d] = result; | 
|  | 2596 | if setflags then | 
|  | 2597 | APSR.N = result<31>; | 
|  | 2598 | APSR.Z = IsZeroBit(result); | 
|  | 2599 | APSR.C = carry; | 
|  | 2600 | APSR.V = overflow; | 
|  | 2601 | #endif | 
|  | 2602 |  | 
|  | 2603 | bool success = false; | 
| Johnny Chen | 26863dc | 2011-02-09 23:43:29 +0000 | [diff] [blame] | 2604 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 2605 | if (ConditionPassed(opcode)) | 
| Johnny Chen | 26863dc | 2011-02-09 23:43:29 +0000 | [diff] [blame] | 2606 | { | 
|  | 2607 | uint32_t Rd, Rn, Rm; | 
| Johnny Chen | d761dcf | 2011-02-17 22:03:29 +0000 | [diff] [blame] | 2608 | ARM_ShifterType shift_t; | 
|  | 2609 | uint32_t shift_n; // the shift applied to the value read from Rm | 
| Johnny Chen | ca67d1c | 2011-02-17 01:35:27 +0000 | [diff] [blame] | 2610 | bool setflags; | 
| Johnny Chen | 26863dc | 2011-02-09 23:43:29 +0000 | [diff] [blame] | 2611 | switch (encoding) | 
|  | 2612 | { | 
| Johnny Chen | d761dcf | 2011-02-17 22:03:29 +0000 | [diff] [blame] | 2613 | case eEncodingT1: | 
|  | 2614 | Rd = Bits32(opcode, 2, 0); | 
|  | 2615 | Rn = Bits32(opcode, 5, 3); | 
|  | 2616 | Rm = Bits32(opcode, 8, 6); | 
|  | 2617 | setflags = !InITBlock(); | 
|  | 2618 | shift_t = SRType_LSL; | 
|  | 2619 | shift_n = 0; | 
| Johnny Chen | ed32e7c | 2011-02-22 23:42:58 +0000 | [diff] [blame] | 2620 | break; | 
| Johnny Chen | 26863dc | 2011-02-09 23:43:29 +0000 | [diff] [blame] | 2621 | case eEncodingT2: | 
| Johnny Chen | bd59990 | 2011-02-10 21:39:01 +0000 | [diff] [blame] | 2622 | Rd = Rn = Bit32(opcode, 7) << 3 | Bits32(opcode, 2, 0); | 
| Johnny Chen | 26863dc | 2011-02-09 23:43:29 +0000 | [diff] [blame] | 2623 | Rm = Bits32(opcode, 6, 3); | 
| Johnny Chen | ca67d1c | 2011-02-17 01:35:27 +0000 | [diff] [blame] | 2624 | setflags = false; | 
| Johnny Chen | d761dcf | 2011-02-17 22:03:29 +0000 | [diff] [blame] | 2625 | shift_t = SRType_LSL; | 
|  | 2626 | shift_n = 0; | 
| Johnny Chen | 26863dc | 2011-02-09 23:43:29 +0000 | [diff] [blame] | 2627 | if (Rn == 15 && Rm == 15) | 
|  | 2628 | return false; | 
| Johnny Chen | d761dcf | 2011-02-17 22:03:29 +0000 | [diff] [blame] | 2629 | if (Rd == 15 && InITBlock() && !LastInITBlock()) | 
|  | 2630 | return false; | 
| Johnny Chen | 26863dc | 2011-02-09 23:43:29 +0000 | [diff] [blame] | 2631 | break; | 
| Johnny Chen | 8fa2059 | 2011-02-18 01:22:22 +0000 | [diff] [blame] | 2632 | case eEncodingA1: | 
|  | 2633 | Rd = Bits32(opcode, 15, 12); | 
|  | 2634 | Rn = Bits32(opcode, 19, 16); | 
|  | 2635 | Rm = Bits32(opcode, 3, 0); | 
|  | 2636 | setflags = BitIsSet(opcode, 20); | 
| Johnny Chen | 3dd0605 | 2011-02-22 21:17:52 +0000 | [diff] [blame] | 2637 | shift_n = DecodeImmShiftARM(opcode, shift_t); | 
| Johnny Chen | 8fa2059 | 2011-02-18 01:22:22 +0000 | [diff] [blame] | 2638 | break; | 
| Johnny Chen | 26863dc | 2011-02-09 23:43:29 +0000 | [diff] [blame] | 2639 | default: | 
|  | 2640 | return false; | 
|  | 2641 | } | 
|  | 2642 |  | 
| Johnny Chen | 26863dc | 2011-02-09 23:43:29 +0000 | [diff] [blame] | 2643 | // Read the first operand. | 
| Johnny Chen | 157b959 | 2011-02-18 21:13:05 +0000 | [diff] [blame] | 2644 | uint32_t val1 = ReadCoreReg(Rn, &success); | 
| Johnny Chen | 26863dc | 2011-02-09 23:43:29 +0000 | [diff] [blame] | 2645 | if (!success) | 
|  | 2646 | return false; | 
|  | 2647 |  | 
|  | 2648 | // Read the second operand. | 
| Johnny Chen | 157b959 | 2011-02-18 21:13:05 +0000 | [diff] [blame] | 2649 | uint32_t val2 = ReadCoreReg(Rm, &success); | 
| Johnny Chen | 26863dc | 2011-02-09 23:43:29 +0000 | [diff] [blame] | 2650 | if (!success) | 
|  | 2651 | return false; | 
|  | 2652 |  | 
| Johnny Chen | a4438a7 | 2011-06-02 22:50:51 +0000 | [diff] [blame] | 2653 | uint32_t shifted = Shift(val2, shift_t, shift_n, APSR_C, &success); | 
|  | 2654 | if (!success) | 
|  | 2655 | return false; | 
| Johnny Chen | 8fa2059 | 2011-02-18 01:22:22 +0000 | [diff] [blame] | 2656 | AddWithCarryResult res = AddWithCarry(val1, shifted, 0); | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 2657 |  | 
|  | 2658 | EmulateInstruction::Context context; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 2659 | context.type = eContextArithmetic; | 
|  | 2660 | RegisterInfo op1_reg; | 
|  | 2661 | RegisterInfo op2_reg; | 
|  | 2662 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + Rn, op1_reg); | 
|  | 2663 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + Rm, op2_reg); | 
| Caroline Tice | 8ce836d | 2011-03-16 22:46:55 +0000 | [diff] [blame] | 2664 | context.SetRegisterRegisterOperands (op1_reg, op2_reg); | 
| Johnny Chen | ca67d1c | 2011-02-17 01:35:27 +0000 | [diff] [blame] | 2665 |  | 
| Johnny Chen | 10530c2 | 2011-02-17 22:37:12 +0000 | [diff] [blame] | 2666 | if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, res.carry_out, res.overflow)) | 
| Johnny Chen | ca67d1c | 2011-02-17 01:35:27 +0000 | [diff] [blame] | 2667 | return false; | 
| Johnny Chen | 26863dc | 2011-02-09 23:43:29 +0000 | [diff] [blame] | 2668 | } | 
|  | 2669 | return true; | 
|  | 2670 | } | 
|  | 2671 |  | 
| Johnny Chen | 34075cb | 2011-02-22 01:56:31 +0000 | [diff] [blame] | 2672 | // Compare Negative (immediate) adds a register value and an immediate value. | 
|  | 2673 | // It updates the condition flags based on the result, and discards the result. | 
| Johnny Chen | d4dc444 | 2011-02-11 02:02:56 +0000 | [diff] [blame] | 2674 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 2675 | EmulateInstructionARM::EmulateCMNImm (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | 34075cb | 2011-02-22 01:56:31 +0000 | [diff] [blame] | 2676 | { | 
|  | 2677 | #if 0 | 
|  | 2678 | // ARM pseudo code... | 
|  | 2679 | if ConditionPassed() then | 
|  | 2680 | EncodingSpecificOperations(); | 
|  | 2681 | (result, carry, overflow) = AddWithCarry(R[n], imm32, '0'); | 
|  | 2682 | APSR.N = result<31>; | 
|  | 2683 | APSR.Z = IsZeroBit(result); | 
|  | 2684 | APSR.C = carry; | 
|  | 2685 | APSR.V = overflow; | 
|  | 2686 | #endif | 
|  | 2687 |  | 
|  | 2688 | bool success = false; | 
| Johnny Chen | 34075cb | 2011-02-22 01:56:31 +0000 | [diff] [blame] | 2689 |  | 
|  | 2690 | uint32_t Rn; // the first operand | 
|  | 2691 | uint32_t imm32; // the immediate value to be compared with | 
|  | 2692 | switch (encoding) { | 
|  | 2693 | case eEncodingT1: | 
| Johnny Chen | 078fbc6 | 2011-02-22 19:48:22 +0000 | [diff] [blame] | 2694 | Rn = Bits32(opcode, 19, 16); | 
|  | 2695 | imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8) | 
|  | 2696 | if (Rn == 15) | 
|  | 2697 | return false; | 
| Johnny Chen | ed32e7c | 2011-02-22 23:42:58 +0000 | [diff] [blame] | 2698 | break; | 
| Johnny Chen | 34075cb | 2011-02-22 01:56:31 +0000 | [diff] [blame] | 2699 | case eEncodingA1: | 
|  | 2700 | Rn = Bits32(opcode, 19, 16); | 
|  | 2701 | imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12) | 
|  | 2702 | break; | 
|  | 2703 | default: | 
|  | 2704 | return false; | 
|  | 2705 | } | 
|  | 2706 | // Read the register value from the operand register Rn. | 
|  | 2707 | uint32_t reg_val = ReadCoreReg(Rn, &success); | 
|  | 2708 | if (!success) | 
|  | 2709 | return false; | 
|  | 2710 |  | 
| Johnny Chen | 078fbc6 | 2011-02-22 19:48:22 +0000 | [diff] [blame] | 2711 | AddWithCarryResult res = AddWithCarry(reg_val, imm32, 0); | 
| Johnny Chen | 34075cb | 2011-02-22 01:56:31 +0000 | [diff] [blame] | 2712 |  | 
|  | 2713 | EmulateInstruction::Context context; | 
|  | 2714 | context.type = EmulateInstruction::eContextImmediate; | 
|  | 2715 | context.SetNoArgs (); | 
|  | 2716 | if (!WriteFlags(context, res.result, res.carry_out, res.overflow)) | 
|  | 2717 | return false; | 
|  | 2718 |  | 
|  | 2719 | return true; | 
|  | 2720 | } | 
|  | 2721 |  | 
|  | 2722 | // Compare Negative (register) adds a register value and an optionally-shifted register value. | 
|  | 2723 | // It updates the condition flags based on the result, and discards the result. | 
|  | 2724 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 2725 | EmulateInstructionARM::EmulateCMNReg (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | 34075cb | 2011-02-22 01:56:31 +0000 | [diff] [blame] | 2726 | { | 
|  | 2727 | #if 0 | 
|  | 2728 | // ARM pseudo code... | 
|  | 2729 | if ConditionPassed() then | 
|  | 2730 | EncodingSpecificOperations(); | 
|  | 2731 | shifted = Shift(R[m], shift_t, shift_n, APSR.C); | 
|  | 2732 | (result, carry, overflow) = AddWithCarry(R[n], shifted, '0'); | 
|  | 2733 | APSR.N = result<31>; | 
|  | 2734 | APSR.Z = IsZeroBit(result); | 
|  | 2735 | APSR.C = carry; | 
|  | 2736 | APSR.V = overflow; | 
|  | 2737 | #endif | 
|  | 2738 |  | 
|  | 2739 | bool success = false; | 
| Johnny Chen | 34075cb | 2011-02-22 01:56:31 +0000 | [diff] [blame] | 2740 |  | 
|  | 2741 | uint32_t Rn; // the first operand | 
|  | 2742 | uint32_t Rm; // the second operand | 
|  | 2743 | ARM_ShifterType shift_t; | 
|  | 2744 | uint32_t shift_n; // the shift applied to the value read from Rm | 
|  | 2745 | switch (encoding) { | 
|  | 2746 | case eEncodingT1: | 
|  | 2747 | Rn = Bits32(opcode, 2, 0); | 
|  | 2748 | Rm = Bits32(opcode, 5, 3); | 
|  | 2749 | shift_t = SRType_LSL; | 
|  | 2750 | shift_n = 0; | 
|  | 2751 | break; | 
|  | 2752 | case eEncodingT2: | 
| Johnny Chen | 078fbc6 | 2011-02-22 19:48:22 +0000 | [diff] [blame] | 2753 | Rn = Bits32(opcode, 19, 16); | 
|  | 2754 | Rm = Bits32(opcode, 3, 0); | 
| Johnny Chen | 3dd0605 | 2011-02-22 21:17:52 +0000 | [diff] [blame] | 2755 | shift_n = DecodeImmShiftThumb(opcode, shift_t); | 
| Johnny Chen | 078fbc6 | 2011-02-22 19:48:22 +0000 | [diff] [blame] | 2756 | // if n == 15 || BadReg(m) then UNPREDICTABLE; | 
|  | 2757 | if (Rn == 15 || BadReg(Rm)) | 
| Johnny Chen | 34075cb | 2011-02-22 01:56:31 +0000 | [diff] [blame] | 2758 | return false; | 
|  | 2759 | break; | 
|  | 2760 | case eEncodingA1: | 
|  | 2761 | Rn = Bits32(opcode, 19, 16); | 
|  | 2762 | Rm = Bits32(opcode, 3, 0); | 
| Johnny Chen | 3dd0605 | 2011-02-22 21:17:52 +0000 | [diff] [blame] | 2763 | shift_n = DecodeImmShiftARM(opcode, shift_t); | 
| Johnny Chen | ed32e7c | 2011-02-22 23:42:58 +0000 | [diff] [blame] | 2764 | break; | 
| Johnny Chen | 34075cb | 2011-02-22 01:56:31 +0000 | [diff] [blame] | 2765 | default: | 
|  | 2766 | return false; | 
|  | 2767 | } | 
|  | 2768 | // Read the register value from register Rn. | 
|  | 2769 | uint32_t val1 = ReadCoreReg(Rn, &success); | 
|  | 2770 | if (!success) | 
|  | 2771 | return false; | 
|  | 2772 |  | 
|  | 2773 | // Read the register value from register Rm. | 
|  | 2774 | uint32_t val2 = ReadCoreReg(Rm, &success); | 
|  | 2775 | if (!success) | 
|  | 2776 | return false; | 
|  | 2777 |  | 
| Johnny Chen | a4438a7 | 2011-06-02 22:50:51 +0000 | [diff] [blame] | 2778 | uint32_t shifted = Shift(val2, shift_t, shift_n, APSR_C, &success); | 
|  | 2779 | if (!success) | 
|  | 2780 | return false; | 
| Johnny Chen | 078fbc6 | 2011-02-22 19:48:22 +0000 | [diff] [blame] | 2781 | AddWithCarryResult res = AddWithCarry(val1, shifted, 0); | 
| Johnny Chen | 34075cb | 2011-02-22 01:56:31 +0000 | [diff] [blame] | 2782 |  | 
|  | 2783 | EmulateInstruction::Context context; | 
|  | 2784 | context.type = EmulateInstruction::eContextImmediate; | 
|  | 2785 | context.SetNoArgs(); | 
|  | 2786 | if (!WriteFlags(context, res.result, res.carry_out, res.overflow)) | 
|  | 2787 | return false; | 
|  | 2788 |  | 
|  | 2789 | return true; | 
|  | 2790 | } | 
|  | 2791 |  | 
|  | 2792 | // Compare (immediate) subtracts an immediate value from a register value. | 
|  | 2793 | // It updates the condition flags based on the result, and discards the result. | 
|  | 2794 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 2795 | EmulateInstructionARM::EmulateCMPImm (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | d4dc444 | 2011-02-11 02:02:56 +0000 | [diff] [blame] | 2796 | { | 
|  | 2797 | #if 0 | 
|  | 2798 | // ARM pseudo code... | 
|  | 2799 | if ConditionPassed() then | 
|  | 2800 | EncodingSpecificOperations(); | 
|  | 2801 | (result, carry, overflow) = AddWithCarry(R[n], NOT(imm32), '1'); | 
|  | 2802 | APSR.N = result<31>; | 
|  | 2803 | APSR.Z = IsZeroBit(result); | 
|  | 2804 | APSR.C = carry; | 
|  | 2805 | APSR.V = overflow; | 
|  | 2806 | #endif | 
|  | 2807 |  | 
|  | 2808 | bool success = false; | 
| Johnny Chen | d4dc444 | 2011-02-11 02:02:56 +0000 | [diff] [blame] | 2809 |  | 
|  | 2810 | uint32_t Rn; // the first operand | 
|  | 2811 | uint32_t imm32; // the immediate value to be compared with | 
|  | 2812 | switch (encoding) { | 
|  | 2813 | case eEncodingT1: | 
|  | 2814 | Rn = Bits32(opcode, 10, 8); | 
|  | 2815 | imm32 = Bits32(opcode, 7, 0); | 
| Johnny Chen | ed32e7c | 2011-02-22 23:42:58 +0000 | [diff] [blame] | 2816 | break; | 
| Johnny Chen | 078fbc6 | 2011-02-22 19:48:22 +0000 | [diff] [blame] | 2817 | case eEncodingT2: | 
|  | 2818 | Rn = Bits32(opcode, 19, 16); | 
|  | 2819 | imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8) | 
|  | 2820 | if (Rn == 15) | 
|  | 2821 | return false; | 
| Johnny Chen | ed32e7c | 2011-02-22 23:42:58 +0000 | [diff] [blame] | 2822 | break; | 
| Johnny Chen | 34075cb | 2011-02-22 01:56:31 +0000 | [diff] [blame] | 2823 | case eEncodingA1: | 
|  | 2824 | Rn = Bits32(opcode, 19, 16); | 
|  | 2825 | imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12) | 
| Johnny Chen | d4dc444 | 2011-02-11 02:02:56 +0000 | [diff] [blame] | 2826 | break; | 
|  | 2827 | default: | 
|  | 2828 | return false; | 
|  | 2829 | } | 
|  | 2830 | // Read the register value from the operand register Rn. | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 2831 | uint32_t reg_val = ReadCoreReg(Rn, &success); | 
| Johnny Chen | d4dc444 | 2011-02-11 02:02:56 +0000 | [diff] [blame] | 2832 | if (!success) | 
|  | 2833 | return false; | 
|  | 2834 |  | 
| Johnny Chen | 10530c2 | 2011-02-17 22:37:12 +0000 | [diff] [blame] | 2835 | AddWithCarryResult res = AddWithCarry(reg_val, ~imm32, 1); | 
|  | 2836 |  | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 2837 | EmulateInstruction::Context context; | 
|  | 2838 | context.type = EmulateInstruction::eContextImmediate; | 
|  | 2839 | context.SetNoArgs (); | 
| Johnny Chen | 10530c2 | 2011-02-17 22:37:12 +0000 | [diff] [blame] | 2840 | if (!WriteFlags(context, res.result, res.carry_out, res.overflow)) | 
|  | 2841 | return false; | 
|  | 2842 |  | 
| Johnny Chen | d4dc444 | 2011-02-11 02:02:56 +0000 | [diff] [blame] | 2843 | return true; | 
|  | 2844 | } | 
|  | 2845 |  | 
| Johnny Chen | 34075cb | 2011-02-22 01:56:31 +0000 | [diff] [blame] | 2846 | // Compare (register) subtracts an optionally-shifted register value from a register value. | 
|  | 2847 | // It updates the condition flags based on the result, and discards the result. | 
| Johnny Chen | e4a4d30 | 2011-02-11 21:53:58 +0000 | [diff] [blame] | 2848 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 2849 | EmulateInstructionARM::EmulateCMPReg (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | e4a4d30 | 2011-02-11 21:53:58 +0000 | [diff] [blame] | 2850 | { | 
|  | 2851 | #if 0 | 
|  | 2852 | // ARM pseudo code... | 
|  | 2853 | if ConditionPassed() then | 
|  | 2854 | EncodingSpecificOperations(); | 
|  | 2855 | shifted = Shift(R[m], shift_t, shift_n, APSR.C); | 
|  | 2856 | (result, carry, overflow) = AddWithCarry(R[n], NOT(shifted), '1'); | 
|  | 2857 | APSR.N = result<31>; | 
|  | 2858 | APSR.Z = IsZeroBit(result); | 
|  | 2859 | APSR.C = carry; | 
|  | 2860 | APSR.V = overflow; | 
|  | 2861 | #endif | 
|  | 2862 |  | 
|  | 2863 | bool success = false; | 
| Johnny Chen | e4a4d30 | 2011-02-11 21:53:58 +0000 | [diff] [blame] | 2864 |  | 
|  | 2865 | uint32_t Rn; // the first operand | 
|  | 2866 | uint32_t Rm; // the second operand | 
| Johnny Chen | 34075cb | 2011-02-22 01:56:31 +0000 | [diff] [blame] | 2867 | ARM_ShifterType shift_t; | 
|  | 2868 | uint32_t shift_n; // the shift applied to the value read from Rm | 
| Johnny Chen | e4a4d30 | 2011-02-11 21:53:58 +0000 | [diff] [blame] | 2869 | switch (encoding) { | 
|  | 2870 | case eEncodingT1: | 
|  | 2871 | Rn = Bits32(opcode, 2, 0); | 
|  | 2872 | Rm = Bits32(opcode, 5, 3); | 
| Johnny Chen | 34075cb | 2011-02-22 01:56:31 +0000 | [diff] [blame] | 2873 | shift_t = SRType_LSL; | 
|  | 2874 | shift_n = 0; | 
| Johnny Chen | e4a4d30 | 2011-02-11 21:53:58 +0000 | [diff] [blame] | 2875 | break; | 
|  | 2876 | case eEncodingT2: | 
|  | 2877 | Rn = Bit32(opcode, 7) << 3 | Bits32(opcode, 2, 0); | 
|  | 2878 | Rm = Bits32(opcode, 6, 3); | 
| Johnny Chen | 34075cb | 2011-02-22 01:56:31 +0000 | [diff] [blame] | 2879 | shift_t = SRType_LSL; | 
|  | 2880 | shift_n = 0; | 
| Johnny Chen | e4a4d30 | 2011-02-11 21:53:58 +0000 | [diff] [blame] | 2881 | if (Rn < 8 && Rm < 8) | 
|  | 2882 | return false; | 
|  | 2883 | if (Rn == 15 || Rm == 15) | 
|  | 2884 | return false; | 
|  | 2885 | break; | 
| Johnny Chen | 34075cb | 2011-02-22 01:56:31 +0000 | [diff] [blame] | 2886 | case eEncodingA1: | 
|  | 2887 | Rn = Bits32(opcode, 19, 16); | 
|  | 2888 | Rm = Bits32(opcode, 3, 0); | 
| Johnny Chen | 3dd0605 | 2011-02-22 21:17:52 +0000 | [diff] [blame] | 2889 | shift_n = DecodeImmShiftARM(opcode, shift_t); | 
| Johnny Chen | ed32e7c | 2011-02-22 23:42:58 +0000 | [diff] [blame] | 2890 | break; | 
| Johnny Chen | e4a4d30 | 2011-02-11 21:53:58 +0000 | [diff] [blame] | 2891 | default: | 
|  | 2892 | return false; | 
|  | 2893 | } | 
|  | 2894 | // Read the register value from register Rn. | 
| Johnny Chen | 34075cb | 2011-02-22 01:56:31 +0000 | [diff] [blame] | 2895 | uint32_t val1 = ReadCoreReg(Rn, &success); | 
| Johnny Chen | e4a4d30 | 2011-02-11 21:53:58 +0000 | [diff] [blame] | 2896 | if (!success) | 
|  | 2897 | return false; | 
| Johnny Chen | 34075cb | 2011-02-22 01:56:31 +0000 | [diff] [blame] | 2898 |  | 
| Johnny Chen | e4a4d30 | 2011-02-11 21:53:58 +0000 | [diff] [blame] | 2899 | // Read the register value from register Rm. | 
| Johnny Chen | 34075cb | 2011-02-22 01:56:31 +0000 | [diff] [blame] | 2900 | uint32_t val2 = ReadCoreReg(Rm, &success); | 
| Johnny Chen | e4a4d30 | 2011-02-11 21:53:58 +0000 | [diff] [blame] | 2901 | if (!success) | 
|  | 2902 | return false; | 
|  | 2903 |  | 
| Johnny Chen | a4438a7 | 2011-06-02 22:50:51 +0000 | [diff] [blame] | 2904 | uint32_t shifted = Shift(val2, shift_t, shift_n, APSR_C, &success); | 
|  | 2905 | if (!success) | 
|  | 2906 | return false; | 
| Johnny Chen | 34075cb | 2011-02-22 01:56:31 +0000 | [diff] [blame] | 2907 | AddWithCarryResult res = AddWithCarry(val1, ~shifted, 1); | 
| Johnny Chen | 10530c2 | 2011-02-17 22:37:12 +0000 | [diff] [blame] | 2908 |  | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 2909 | EmulateInstruction::Context context; | 
|  | 2910 | context.type = EmulateInstruction::eContextImmediate; | 
|  | 2911 | context.SetNoArgs(); | 
| Johnny Chen | 10530c2 | 2011-02-17 22:37:12 +0000 | [diff] [blame] | 2912 | if (!WriteFlags(context, res.result, res.carry_out, res.overflow)) | 
|  | 2913 | return false; | 
|  | 2914 |  | 
| Johnny Chen | e4a4d30 | 2011-02-11 21:53:58 +0000 | [diff] [blame] | 2915 | return true; | 
|  | 2916 | } | 
|  | 2917 |  | 
| Johnny Chen | 82f16aa | 2011-02-15 20:10:55 +0000 | [diff] [blame] | 2918 | // Arithmetic Shift Right (immediate) shifts a register value right by an immediate number of bits, | 
|  | 2919 | // shifting in copies of its sign bit, and writes the result to the destination register.  It can | 
|  | 2920 | // optionally update the condition flags based on the result. | 
|  | 2921 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 2922 | EmulateInstructionARM::EmulateASRImm (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | 82f16aa | 2011-02-15 20:10:55 +0000 | [diff] [blame] | 2923 | { | 
|  | 2924 | #if 0 | 
|  | 2925 | // ARM pseudo code... | 
|  | 2926 | if ConditionPassed() then | 
|  | 2927 | EncodingSpecificOperations(); | 
|  | 2928 | (result, carry) = Shift_C(R[m], SRType_ASR, shift_n, APSR.C); | 
|  | 2929 | if d == 15 then         // Can only occur for ARM encoding | 
|  | 2930 | ALUWritePC(result); // setflags is always FALSE here | 
|  | 2931 | else | 
|  | 2932 | R[d] = result; | 
|  | 2933 | if setflags then | 
|  | 2934 | APSR.N = result<31>; | 
|  | 2935 | APSR.Z = IsZeroBit(result); | 
|  | 2936 | APSR.C = carry; | 
|  | 2937 | // APSR.V unchanged | 
|  | 2938 | #endif | 
|  | 2939 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 2940 | return EmulateShiftImm (opcode, encoding, SRType_ASR); | 
| Johnny Chen | 41a0a15 | 2011-02-16 01:27:54 +0000 | [diff] [blame] | 2941 | } | 
|  | 2942 |  | 
|  | 2943 | // Arithmetic Shift Right (register) shifts a register value right by a variable number of bits, | 
|  | 2944 | // shifting in copies of its sign bit, and writes the result to the destination register. | 
|  | 2945 | // The variable number of bits is read from the bottom byte of a register. It can optionally update | 
|  | 2946 | // the condition flags based on the result. | 
|  | 2947 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 2948 | EmulateInstructionARM::EmulateASRReg (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | 41a0a15 | 2011-02-16 01:27:54 +0000 | [diff] [blame] | 2949 | { | 
|  | 2950 | #if 0 | 
|  | 2951 | // ARM pseudo code... | 
|  | 2952 | if ConditionPassed() then | 
|  | 2953 | EncodingSpecificOperations(); | 
|  | 2954 | shift_n = UInt(R[m]<7:0>); | 
|  | 2955 | (result, carry) = Shift_C(R[m], SRType_ASR, shift_n, APSR.C); | 
|  | 2956 | R[d] = result; | 
|  | 2957 | if setflags then | 
|  | 2958 | APSR.N = result<31>; | 
|  | 2959 | APSR.Z = IsZeroBit(result); | 
|  | 2960 | APSR.C = carry; | 
|  | 2961 | // APSR.V unchanged | 
|  | 2962 | #endif | 
|  | 2963 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 2964 | return EmulateShiftReg (opcode, encoding, SRType_ASR); | 
| Johnny Chen | 41a0a15 | 2011-02-16 01:27:54 +0000 | [diff] [blame] | 2965 | } | 
|  | 2966 |  | 
|  | 2967 | // Logical Shift Left (immediate) shifts a register value left by an immediate number of bits, | 
|  | 2968 | // shifting in zeros, and writes the result to the destination register.  It can optionally | 
|  | 2969 | // update the condition flags based on the result. | 
|  | 2970 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 2971 | EmulateInstructionARM::EmulateLSLImm (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | 41a0a15 | 2011-02-16 01:27:54 +0000 | [diff] [blame] | 2972 | { | 
|  | 2973 | #if 0 | 
|  | 2974 | // ARM pseudo code... | 
|  | 2975 | if ConditionPassed() then | 
|  | 2976 | EncodingSpecificOperations(); | 
|  | 2977 | (result, carry) = Shift_C(R[m], SRType_LSL, shift_n, APSR.C); | 
|  | 2978 | if d == 15 then         // Can only occur for ARM encoding | 
|  | 2979 | ALUWritePC(result); // setflags is always FALSE here | 
|  | 2980 | else | 
|  | 2981 | R[d] = result; | 
|  | 2982 | if setflags then | 
|  | 2983 | APSR.N = result<31>; | 
|  | 2984 | APSR.Z = IsZeroBit(result); | 
|  | 2985 | APSR.C = carry; | 
|  | 2986 | // APSR.V unchanged | 
|  | 2987 | #endif | 
|  | 2988 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 2989 | return EmulateShiftImm (opcode, encoding, SRType_LSL); | 
| Johnny Chen | 41a0a15 | 2011-02-16 01:27:54 +0000 | [diff] [blame] | 2990 | } | 
|  | 2991 |  | 
|  | 2992 | // Logical Shift Left (register) shifts a register value left by a variable number of bits, | 
|  | 2993 | // shifting in zeros, and writes the result to the destination register.  The variable number | 
|  | 2994 | // of bits is read from the bottom byte of a register. It can optionally update the condition | 
|  | 2995 | // flags based on the result. | 
|  | 2996 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 2997 | EmulateInstructionARM::EmulateLSLReg (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | 41a0a15 | 2011-02-16 01:27:54 +0000 | [diff] [blame] | 2998 | { | 
|  | 2999 | #if 0 | 
|  | 3000 | // ARM pseudo code... | 
|  | 3001 | if ConditionPassed() then | 
|  | 3002 | EncodingSpecificOperations(); | 
|  | 3003 | shift_n = UInt(R[m]<7:0>); | 
|  | 3004 | (result, carry) = Shift_C(R[m], SRType_LSL, shift_n, APSR.C); | 
|  | 3005 | R[d] = result; | 
|  | 3006 | if setflags then | 
|  | 3007 | APSR.N = result<31>; | 
|  | 3008 | APSR.Z = IsZeroBit(result); | 
|  | 3009 | APSR.C = carry; | 
|  | 3010 | // APSR.V unchanged | 
|  | 3011 | #endif | 
|  | 3012 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 3013 | return EmulateShiftReg (opcode, encoding, SRType_LSL); | 
| Johnny Chen | 41a0a15 | 2011-02-16 01:27:54 +0000 | [diff] [blame] | 3014 | } | 
|  | 3015 |  | 
|  | 3016 | // Logical Shift Right (immediate) shifts a register value right by an immediate number of bits, | 
|  | 3017 | // shifting in zeros, and writes the result to the destination register.  It can optionally | 
|  | 3018 | // update the condition flags based on the result. | 
|  | 3019 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 3020 | EmulateInstructionARM::EmulateLSRImm (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | 41a0a15 | 2011-02-16 01:27:54 +0000 | [diff] [blame] | 3021 | { | 
|  | 3022 | #if 0 | 
|  | 3023 | // ARM pseudo code... | 
|  | 3024 | if ConditionPassed() then | 
|  | 3025 | EncodingSpecificOperations(); | 
|  | 3026 | (result, carry) = Shift_C(R[m], SRType_LSR, shift_n, APSR.C); | 
|  | 3027 | if d == 15 then         // Can only occur for ARM encoding | 
|  | 3028 | ALUWritePC(result); // setflags is always FALSE here | 
|  | 3029 | else | 
|  | 3030 | R[d] = result; | 
|  | 3031 | if setflags then | 
|  | 3032 | APSR.N = result<31>; | 
|  | 3033 | APSR.Z = IsZeroBit(result); | 
|  | 3034 | APSR.C = carry; | 
|  | 3035 | // APSR.V unchanged | 
|  | 3036 | #endif | 
|  | 3037 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 3038 | return EmulateShiftImm (opcode, encoding, SRType_LSR); | 
| Johnny Chen | 41a0a15 | 2011-02-16 01:27:54 +0000 | [diff] [blame] | 3039 | } | 
|  | 3040 |  | 
|  | 3041 | // Logical Shift Right (register) shifts a register value right by a variable number of bits, | 
|  | 3042 | // shifting in zeros, and writes the result to the destination register.  The variable number | 
|  | 3043 | // of bits is read from the bottom byte of a register. It can optionally update the condition | 
|  | 3044 | // flags based on the result. | 
|  | 3045 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 3046 | EmulateInstructionARM::EmulateLSRReg (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | 41a0a15 | 2011-02-16 01:27:54 +0000 | [diff] [blame] | 3047 | { | 
|  | 3048 | #if 0 | 
|  | 3049 | // ARM pseudo code... | 
|  | 3050 | if ConditionPassed() then | 
|  | 3051 | EncodingSpecificOperations(); | 
|  | 3052 | shift_n = UInt(R[m]<7:0>); | 
|  | 3053 | (result, carry) = Shift_C(R[m], SRType_LSR, shift_n, APSR.C); | 
|  | 3054 | R[d] = result; | 
|  | 3055 | if setflags then | 
|  | 3056 | APSR.N = result<31>; | 
|  | 3057 | APSR.Z = IsZeroBit(result); | 
|  | 3058 | APSR.C = carry; | 
|  | 3059 | // APSR.V unchanged | 
|  | 3060 | #endif | 
|  | 3061 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 3062 | return EmulateShiftReg (opcode, encoding, SRType_LSR); | 
| Johnny Chen | 41a0a15 | 2011-02-16 01:27:54 +0000 | [diff] [blame] | 3063 | } | 
|  | 3064 |  | 
| Johnny Chen | eeab485 | 2011-02-16 22:14:44 +0000 | [diff] [blame] | 3065 | // Rotate Right (immediate) provides the value of the contents of a register rotated by a constant value. | 
|  | 3066 | // The bits that are rotated off the right end are inserted into the vacated bit positions on the left. | 
|  | 3067 | // It can optionally update the condition flags based on the result. | 
|  | 3068 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 3069 | EmulateInstructionARM::EmulateRORImm (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | eeab485 | 2011-02-16 22:14:44 +0000 | [diff] [blame] | 3070 | { | 
|  | 3071 | #if 0 | 
|  | 3072 | // ARM pseudo code... | 
|  | 3073 | if ConditionPassed() then | 
|  | 3074 | EncodingSpecificOperations(); | 
|  | 3075 | (result, carry) = Shift_C(R[m], SRType_ROR, shift_n, APSR.C); | 
|  | 3076 | if d == 15 then         // Can only occur for ARM encoding | 
|  | 3077 | ALUWritePC(result); // setflags is always FALSE here | 
|  | 3078 | else | 
|  | 3079 | R[d] = result; | 
|  | 3080 | if setflags then | 
|  | 3081 | APSR.N = result<31>; | 
|  | 3082 | APSR.Z = IsZeroBit(result); | 
|  | 3083 | APSR.C = carry; | 
|  | 3084 | // APSR.V unchanged | 
|  | 3085 | #endif | 
|  | 3086 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 3087 | return EmulateShiftImm (opcode, encoding, SRType_ROR); | 
| Johnny Chen | eeab485 | 2011-02-16 22:14:44 +0000 | [diff] [blame] | 3088 | } | 
|  | 3089 |  | 
|  | 3090 | // Rotate Right (register) provides the value of the contents of a register rotated by a variable number of bits. | 
|  | 3091 | // The bits that are rotated off the right end are inserted into the vacated bit positions on the left. | 
|  | 3092 | // The variable number of bits is read from the bottom byte of a register. It can optionally update the condition | 
|  | 3093 | // flags based on the result. | 
|  | 3094 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 3095 | EmulateInstructionARM::EmulateRORReg (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | eeab485 | 2011-02-16 22:14:44 +0000 | [diff] [blame] | 3096 | { | 
|  | 3097 | #if 0 | 
|  | 3098 | // ARM pseudo code... | 
|  | 3099 | if ConditionPassed() then | 
|  | 3100 | EncodingSpecificOperations(); | 
|  | 3101 | shift_n = UInt(R[m]<7:0>); | 
|  | 3102 | (result, carry) = Shift_C(R[m], SRType_ROR, shift_n, APSR.C); | 
|  | 3103 | R[d] = result; | 
|  | 3104 | if setflags then | 
|  | 3105 | APSR.N = result<31>; | 
|  | 3106 | APSR.Z = IsZeroBit(result); | 
|  | 3107 | APSR.C = carry; | 
|  | 3108 | // APSR.V unchanged | 
|  | 3109 | #endif | 
|  | 3110 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 3111 | return EmulateShiftReg (opcode, encoding, SRType_ROR); | 
| Johnny Chen | eeab485 | 2011-02-16 22:14:44 +0000 | [diff] [blame] | 3112 | } | 
|  | 3113 |  | 
|  | 3114 | // Rotate Right with Extend provides the value of the contents of a register shifted right by one place, | 
|  | 3115 | // with the carry flag shifted into bit [31]. | 
|  | 3116 | // | 
|  | 3117 | // RRX can optionally update the condition flags based on the result. | 
|  | 3118 | // In that case, bit [0] is shifted into the carry flag. | 
|  | 3119 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 3120 | EmulateInstructionARM::EmulateRRX (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | eeab485 | 2011-02-16 22:14:44 +0000 | [diff] [blame] | 3121 | { | 
|  | 3122 | #if 0 | 
|  | 3123 | // ARM pseudo code... | 
|  | 3124 | if ConditionPassed() then | 
|  | 3125 | EncodingSpecificOperations(); | 
|  | 3126 | (result, carry) = Shift_C(R[m], SRType_RRX, 1, APSR.C); | 
|  | 3127 | if d == 15 then         // Can only occur for ARM encoding | 
|  | 3128 | ALUWritePC(result); // setflags is always FALSE here | 
|  | 3129 | else | 
|  | 3130 | R[d] = result; | 
|  | 3131 | if setflags then | 
|  | 3132 | APSR.N = result<31>; | 
|  | 3133 | APSR.Z = IsZeroBit(result); | 
|  | 3134 | APSR.C = carry; | 
|  | 3135 | // APSR.V unchanged | 
|  | 3136 | #endif | 
|  | 3137 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 3138 | return EmulateShiftImm (opcode, encoding, SRType_RRX); | 
| Johnny Chen | eeab485 | 2011-02-16 22:14:44 +0000 | [diff] [blame] | 3139 | } | 
|  | 3140 |  | 
| Johnny Chen | 41a0a15 | 2011-02-16 01:27:54 +0000 | [diff] [blame] | 3141 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 3142 | EmulateInstructionARM::EmulateShiftImm (const uint32_t opcode, const ARMEncoding encoding, ARM_ShifterType shift_type) | 
| Johnny Chen | 41a0a15 | 2011-02-16 01:27:54 +0000 | [diff] [blame] | 3143 | { | 
| Greg Clayton | e1f47bb | 2011-06-02 22:23:35 +0000 | [diff] [blame] | 3144 | //    assert(shift_type == SRType_ASR | 
|  | 3145 | //           || shift_type == SRType_LSL | 
|  | 3146 | //           || shift_type == SRType_LSR | 
|  | 3147 | //           || shift_type == SRType_ROR | 
|  | 3148 | //           || shift_type == SRType_RRX); | 
| Johnny Chen | 41a0a15 | 2011-02-16 01:27:54 +0000 | [diff] [blame] | 3149 |  | 
| Johnny Chen | 82f16aa | 2011-02-15 20:10:55 +0000 | [diff] [blame] | 3150 | bool success = false; | 
| Johnny Chen | 82f16aa | 2011-02-15 20:10:55 +0000 | [diff] [blame] | 3151 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 3152 | if (ConditionPassed(opcode)) | 
| Johnny Chen | 82f16aa | 2011-02-15 20:10:55 +0000 | [diff] [blame] | 3153 | { | 
| Johnny Chen | e7f8953 | 2011-02-15 23:22:46 +0000 | [diff] [blame] | 3154 | uint32_t Rd;    // the destination register | 
|  | 3155 | uint32_t Rm;    // the first operand register | 
|  | 3156 | uint32_t imm5;  // encoding for the shift amount | 
| Johnny Chen | 82f16aa | 2011-02-15 20:10:55 +0000 | [diff] [blame] | 3157 | uint32_t carry; // the carry bit after the shift operation | 
|  | 3158 | bool setflags; | 
| Johnny Chen | eeab485 | 2011-02-16 22:14:44 +0000 | [diff] [blame] | 3159 |  | 
|  | 3160 | // Special case handling! | 
|  | 3161 | // A8.6.139 ROR (immediate) -- Encoding T1 | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 3162 | ARMEncoding use_encoding = encoding; | 
|  | 3163 | if (shift_type == SRType_ROR && use_encoding == eEncodingT1) | 
| Johnny Chen | eeab485 | 2011-02-16 22:14:44 +0000 | [diff] [blame] | 3164 | { | 
|  | 3165 | // Morph the T1 encoding from the ARM Architecture Manual into T2 encoding to | 
|  | 3166 | // have the same decoding of bit fields as the other Thumb2 shift operations. | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 3167 | use_encoding = eEncodingT2; | 
| Johnny Chen | eeab485 | 2011-02-16 22:14:44 +0000 | [diff] [blame] | 3168 | } | 
|  | 3169 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 3170 | switch (use_encoding) { | 
| Johnny Chen | 82f16aa | 2011-02-15 20:10:55 +0000 | [diff] [blame] | 3171 | case eEncodingT1: | 
| Johnny Chen | eeab485 | 2011-02-16 22:14:44 +0000 | [diff] [blame] | 3172 | // Due to the above special case handling! | 
| Johnny Chen | 6cc6097 | 2011-06-02 23:07:03 +0000 | [diff] [blame] | 3173 | if (shift_type == SRType_ROR) | 
|  | 3174 | return false; | 
| Johnny Chen | eeab485 | 2011-02-16 22:14:44 +0000 | [diff] [blame] | 3175 |  | 
| Johnny Chen | 82f16aa | 2011-02-15 20:10:55 +0000 | [diff] [blame] | 3176 | Rd = Bits32(opcode, 2, 0); | 
|  | 3177 | Rm = Bits32(opcode, 5, 3); | 
|  | 3178 | setflags = !InITBlock(); | 
|  | 3179 | imm5 = Bits32(opcode, 10, 6); | 
|  | 3180 | break; | 
|  | 3181 | case eEncodingT2: | 
| Johnny Chen | eeab485 | 2011-02-16 22:14:44 +0000 | [diff] [blame] | 3182 | // A8.6.141 RRX | 
| Johnny Chen | 6cc6097 | 2011-06-02 23:07:03 +0000 | [diff] [blame] | 3183 | // There's no imm form of RRX instructions. | 
|  | 3184 | if (shift_type == SRType_RRX) | 
|  | 3185 | return false; | 
| Johnny Chen | eeab485 | 2011-02-16 22:14:44 +0000 | [diff] [blame] | 3186 |  | 
| Johnny Chen | 82f16aa | 2011-02-15 20:10:55 +0000 | [diff] [blame] | 3187 | Rd = Bits32(opcode, 11, 8); | 
|  | 3188 | Rm = Bits32(opcode, 3, 0); | 
|  | 3189 | setflags = BitIsSet(opcode, 20); | 
|  | 3190 | imm5 = Bits32(opcode, 14, 12) << 2 | Bits32(opcode, 7, 6); | 
|  | 3191 | if (BadReg(Rd) || BadReg(Rm)) | 
|  | 3192 | return false; | 
|  | 3193 | break; | 
|  | 3194 | case eEncodingA1: | 
|  | 3195 | Rd = Bits32(opcode, 15, 12); | 
|  | 3196 | Rm = Bits32(opcode, 3, 0); | 
|  | 3197 | setflags = BitIsSet(opcode, 20); | 
|  | 3198 | imm5 = Bits32(opcode, 11, 7); | 
|  | 3199 | break; | 
|  | 3200 | default: | 
|  | 3201 | return false; | 
|  | 3202 | } | 
|  | 3203 |  | 
| Johnny Chen | eeab485 | 2011-02-16 22:14:44 +0000 | [diff] [blame] | 3204 | // A8.6.139 ROR (immediate) | 
|  | 3205 | if (shift_type == SRType_ROR && imm5 == 0) | 
|  | 3206 | shift_type = SRType_RRX; | 
|  | 3207 |  | 
| Johnny Chen | 82f16aa | 2011-02-15 20:10:55 +0000 | [diff] [blame] | 3208 | // Get the first operand. | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 3209 | uint32_t value = ReadCoreReg (Rm, &success); | 
| Johnny Chen | 82f16aa | 2011-02-15 20:10:55 +0000 | [diff] [blame] | 3210 | if (!success) | 
|  | 3211 | return false; | 
|  | 3212 |  | 
| Johnny Chen | eeab485 | 2011-02-16 22:14:44 +0000 | [diff] [blame] | 3213 | // Decode the shift amount if not RRX. | 
|  | 3214 | uint32_t amt = (shift_type == SRType_RRX ? 1 : DecodeImmShift(shift_type, imm5)); | 
| Johnny Chen | 82f16aa | 2011-02-15 20:10:55 +0000 | [diff] [blame] | 3215 |  | 
| Johnny Chen | a4438a7 | 2011-06-02 22:50:51 +0000 | [diff] [blame] | 3216 | uint32_t result = Shift_C(value, shift_type, amt, APSR_C, carry, &success); | 
|  | 3217 | if (!success) | 
|  | 3218 | return false; | 
| Johnny Chen | 82f16aa | 2011-02-15 20:10:55 +0000 | [diff] [blame] | 3219 |  | 
|  | 3220 | // The context specifies that an immediate is to be moved into Rd. | 
|  | 3221 | EmulateInstruction::Context context; | 
|  | 3222 | context.type = EmulateInstruction::eContextImmediate; | 
|  | 3223 | context.SetNoArgs (); | 
| Johnny Chen | 82f16aa | 2011-02-15 20:10:55 +0000 | [diff] [blame] | 3224 |  | 
| Johnny Chen | 10530c2 | 2011-02-17 22:37:12 +0000 | [diff] [blame] | 3225 | if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry)) | 
| Johnny Chen | ca67d1c | 2011-02-17 01:35:27 +0000 | [diff] [blame] | 3226 | return false; | 
| Johnny Chen | 82f16aa | 2011-02-15 20:10:55 +0000 | [diff] [blame] | 3227 | } | 
|  | 3228 | return true; | 
|  | 3229 | } | 
|  | 3230 |  | 
| Johnny Chen | e7f8953 | 2011-02-15 23:22:46 +0000 | [diff] [blame] | 3231 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 3232 | EmulateInstructionARM::EmulateShiftReg (const uint32_t opcode, const ARMEncoding encoding, ARM_ShifterType shift_type) | 
| Johnny Chen | e7f8953 | 2011-02-15 23:22:46 +0000 | [diff] [blame] | 3233 | { | 
| Greg Clayton | e1f47bb | 2011-06-02 22:23:35 +0000 | [diff] [blame] | 3234 | // assert(shift_type == SRType_ASR | 
|  | 3235 | //        || shift_type == SRType_LSL | 
|  | 3236 | //        || shift_type == SRType_LSR | 
|  | 3237 | //        || shift_type == SRType_ROR); | 
| Johnny Chen | e7f8953 | 2011-02-15 23:22:46 +0000 | [diff] [blame] | 3238 |  | 
|  | 3239 | bool success = false; | 
| Johnny Chen | e7f8953 | 2011-02-15 23:22:46 +0000 | [diff] [blame] | 3240 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 3241 | if (ConditionPassed(opcode)) | 
| Johnny Chen | e7f8953 | 2011-02-15 23:22:46 +0000 | [diff] [blame] | 3242 | { | 
|  | 3243 | uint32_t Rd;    // the destination register | 
|  | 3244 | uint32_t Rn;    // the first operand register | 
|  | 3245 | uint32_t Rm;    // the register whose bottom byte contains the amount to shift by | 
|  | 3246 | uint32_t carry; // the carry bit after the shift operation | 
|  | 3247 | bool setflags; | 
|  | 3248 | switch (encoding) { | 
|  | 3249 | case eEncodingT1: | 
|  | 3250 | Rd = Bits32(opcode, 2, 0); | 
|  | 3251 | Rn = Rd; | 
|  | 3252 | Rm = Bits32(opcode, 5, 3); | 
|  | 3253 | setflags = !InITBlock(); | 
|  | 3254 | break; | 
|  | 3255 | case eEncodingT2: | 
|  | 3256 | Rd = Bits32(opcode, 11, 8); | 
|  | 3257 | Rn = Bits32(opcode, 19, 16); | 
|  | 3258 | Rm = Bits32(opcode, 3, 0); | 
|  | 3259 | setflags = BitIsSet(opcode, 20); | 
|  | 3260 | if (BadReg(Rd) || BadReg(Rn) || BadReg(Rm)) | 
|  | 3261 | return false; | 
|  | 3262 | break; | 
|  | 3263 | case eEncodingA1: | 
|  | 3264 | Rd = Bits32(opcode, 15, 12); | 
|  | 3265 | Rn = Bits32(opcode, 3, 0); | 
|  | 3266 | Rm = Bits32(opcode, 11, 8); | 
|  | 3267 | setflags = BitIsSet(opcode, 20); | 
|  | 3268 | if (Rd == 15 || Rn == 15 || Rm == 15) | 
|  | 3269 | return false; | 
|  | 3270 | break; | 
|  | 3271 | default: | 
|  | 3272 | return false; | 
|  | 3273 | } | 
|  | 3274 |  | 
|  | 3275 | // Get the first operand. | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 3276 | uint32_t value = ReadCoreReg (Rn, &success); | 
| Johnny Chen | e7f8953 | 2011-02-15 23:22:46 +0000 | [diff] [blame] | 3277 | if (!success) | 
|  | 3278 | return false; | 
|  | 3279 | // Get the Rm register content. | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 3280 | uint32_t val = ReadCoreReg (Rm, &success); | 
| Johnny Chen | e7f8953 | 2011-02-15 23:22:46 +0000 | [diff] [blame] | 3281 | if (!success) | 
|  | 3282 | return false; | 
|  | 3283 |  | 
|  | 3284 | // Get the shift amount. | 
|  | 3285 | uint32_t amt = Bits32(val, 7, 0); | 
|  | 3286 |  | 
| Johnny Chen | a4438a7 | 2011-06-02 22:50:51 +0000 | [diff] [blame] | 3287 | uint32_t result = Shift_C(value, shift_type, amt, APSR_C, carry, &success); | 
|  | 3288 | if (!success) | 
|  | 3289 | return false; | 
| Johnny Chen | e7f8953 | 2011-02-15 23:22:46 +0000 | [diff] [blame] | 3290 |  | 
|  | 3291 | // The context specifies that an immediate is to be moved into Rd. | 
|  | 3292 | EmulateInstruction::Context context; | 
|  | 3293 | context.type = EmulateInstruction::eContextImmediate; | 
|  | 3294 | context.SetNoArgs (); | 
|  | 3295 |  | 
| Johnny Chen | 10530c2 | 2011-02-17 22:37:12 +0000 | [diff] [blame] | 3296 | if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry)) | 
| Johnny Chen | e7f8953 | 2011-02-15 23:22:46 +0000 | [diff] [blame] | 3297 | return false; | 
| Johnny Chen | e7f8953 | 2011-02-15 23:22:46 +0000 | [diff] [blame] | 3298 | } | 
|  | 3299 | return true; | 
|  | 3300 | } | 
|  | 3301 |  | 
| Caroline Tice | b9f76c3 | 2011-02-08 22:24:38 +0000 | [diff] [blame] | 3302 | // LDM loads multiple registers from consecutive memory locations, using an | 
| Caroline Tice | 713c266 | 2011-02-11 17:59:55 +0000 | [diff] [blame] | 3303 | // address from a base register.  Optionally the address just above the highest of those locations | 
| Caroline Tice | b9f76c3 | 2011-02-08 22:24:38 +0000 | [diff] [blame] | 3304 | // can be written back to the base register. | 
|  | 3305 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 3306 | EmulateInstructionARM::EmulateLDM (const uint32_t opcode, const ARMEncoding encoding) | 
| Caroline Tice | b9f76c3 | 2011-02-08 22:24:38 +0000 | [diff] [blame] | 3307 | { | 
|  | 3308 | #if 0 | 
|  | 3309 | // ARM pseudo code... | 
|  | 3310 | if ConditionPassed() | 
|  | 3311 | EncodingSpecificOperations(); NullCheckIfThumbEE (n); | 
|  | 3312 | address = R[n]; | 
|  | 3313 |  | 
|  | 3314 | for i = 0 to 14 | 
|  | 3315 | if registers<i> == '1' then | 
|  | 3316 | R[i] = MemA[address, 4]; address = address + 4; | 
|  | 3317 | if registers<15> == '1' then | 
|  | 3318 | LoadWritePC (MemA[address, 4]); | 
|  | 3319 |  | 
|  | 3320 | if wback && registers<n> == '0' then R[n] = R[n] + 4 * BitCount (registers); | 
|  | 3321 | if wback && registers<n> == '1' then R[n] = bits(32) UNKNOWN; // Only possible for encoding A1 | 
|  | 3322 |  | 
|  | 3323 | #endif | 
|  | 3324 |  | 
|  | 3325 | bool success = false; | 
| Greg Clayton | 107e53d | 2011-07-06 04:07:21 +0000 | [diff] [blame] | 3326 | bool conditional = false; | 
|  | 3327 | if (ConditionPassed(opcode, &conditional)) | 
| Caroline Tice | b9f76c3 | 2011-02-08 22:24:38 +0000 | [diff] [blame] | 3328 | { | 
|  | 3329 | uint32_t n; | 
|  | 3330 | uint32_t registers = 0; | 
|  | 3331 | bool wback; | 
|  | 3332 | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  | 3333 | switch (encoding) | 
|  | 3334 | { | 
|  | 3335 | case eEncodingT1: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3336 | // n = UInt(Rn); registers = '00000000':register_list; wback = (registers<n> == '0'); | 
| Caroline Tice | b9f76c3 | 2011-02-08 22:24:38 +0000 | [diff] [blame] | 3337 | n = Bits32 (opcode, 10, 8); | 
|  | 3338 | registers = Bits32 (opcode, 7, 0); | 
| Caroline Tice | b6f8d7e | 2011-02-15 18:10:01 +0000 | [diff] [blame] | 3339 | registers = registers & 0x00ff;  // Make sure the top 8 bits are zeros. | 
| Caroline Tice | b9f76c3 | 2011-02-08 22:24:38 +0000 | [diff] [blame] | 3340 | wback = BitIsClear (registers, n); | 
|  | 3341 | // if BitCount(registers) < 1 then UNPREDICTABLE; | 
|  | 3342 | if (BitCount(registers) < 1) | 
|  | 3343 | return false; | 
|  | 3344 | break; | 
|  | 3345 | case eEncodingT2: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3346 | // if W == '1' && Rn == '1101' then SEE POP; | 
|  | 3347 | // n = UInt(Rn); registers = P:M:'0':register_list; wback = (W == '1'); | 
| Caroline Tice | b9f76c3 | 2011-02-08 22:24:38 +0000 | [diff] [blame] | 3348 | n = Bits32 (opcode, 19, 16); | 
|  | 3349 | registers = Bits32 (opcode, 15, 0); | 
| Caroline Tice | b6f8d7e | 2011-02-15 18:10:01 +0000 | [diff] [blame] | 3350 | registers = registers & 0xdfff; // Make sure bit 13 is zero. | 
| Caroline Tice | b9f76c3 | 2011-02-08 22:24:38 +0000 | [diff] [blame] | 3351 | wback = BitIsSet (opcode, 21); | 
| Caroline Tice | b6f8d7e | 2011-02-15 18:10:01 +0000 | [diff] [blame] | 3352 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3353 | // if n == 15 || BitCount(registers) < 2 || (P == '1' && M == '1') then UNPREDICTABLE; | 
| Caroline Tice | b9f76c3 | 2011-02-08 22:24:38 +0000 | [diff] [blame] | 3354 | if ((n == 15) | 
|  | 3355 | || (BitCount (registers) < 2) | 
|  | 3356 | || (BitIsSet (opcode, 14) && BitIsSet (opcode, 15))) | 
|  | 3357 | return false; | 
| Caroline Tice | b6f8d7e | 2011-02-15 18:10:01 +0000 | [diff] [blame] | 3358 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3359 | // if registers<15> == '1' && InITBlock() && !LastInITBlock() then UNPREDICTABLE; | 
| Johnny Chen | 098ae2d | 2011-02-12 00:50:05 +0000 | [diff] [blame] | 3360 | if (BitIsSet (registers, 15) && InITBlock() && !LastInITBlock()) | 
| Caroline Tice | b9f76c3 | 2011-02-08 22:24:38 +0000 | [diff] [blame] | 3361 | return false; | 
| Caroline Tice | b6f8d7e | 2011-02-15 18:10:01 +0000 | [diff] [blame] | 3362 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3363 | // if wback && registers<n> == '1' then UNPREDICTABLE; | 
| Caroline Tice | b9f76c3 | 2011-02-08 22:24:38 +0000 | [diff] [blame] | 3364 | if (wback | 
|  | 3365 | && BitIsSet (registers, n)) | 
|  | 3366 | return false; | 
|  | 3367 | break; | 
| Caroline Tice | b6f8d7e | 2011-02-15 18:10:01 +0000 | [diff] [blame] | 3368 |  | 
| Caroline Tice | b9f76c3 | 2011-02-08 22:24:38 +0000 | [diff] [blame] | 3369 | case eEncodingA1: | 
|  | 3370 | n = Bits32 (opcode, 19, 16); | 
|  | 3371 | registers = Bits32 (opcode, 15, 0); | 
|  | 3372 | wback = BitIsSet (opcode, 21); | 
|  | 3373 | if ((n == 15) | 
|  | 3374 | || (BitCount (registers) < 1)) | 
|  | 3375 | return false; | 
|  | 3376 | break; | 
|  | 3377 | default: | 
|  | 3378 | return false; | 
|  | 3379 | } | 
|  | 3380 |  | 
|  | 3381 | int32_t offset = 0; | 
|  | 3382 | const addr_t base_address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success); | 
|  | 3383 | if (!success) | 
|  | 3384 | return false; | 
| Caroline Tice | 85aab33 | 2011-02-08 23:56:10 +0000 | [diff] [blame] | 3385 |  | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 3386 | EmulateInstruction::Context context; | 
|  | 3387 | context.type = EmulateInstruction::eContextRegisterPlusOffset; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 3388 | RegisterInfo dwarf_reg; | 
|  | 3389 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, dwarf_reg); | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 3390 | context.SetRegisterPlusOffset (dwarf_reg, offset); | 
| Caroline Tice | b9f76c3 | 2011-02-08 22:24:38 +0000 | [diff] [blame] | 3391 |  | 
|  | 3392 | for (int i = 0; i < 14; ++i) | 
|  | 3393 | { | 
|  | 3394 | if (BitIsSet (registers, i)) | 
|  | 3395 | { | 
| Caroline Tice | 85aab33 | 2011-02-08 23:56:10 +0000 | [diff] [blame] | 3396 | context.type = EmulateInstruction::eContextRegisterPlusOffset; | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 3397 | context.SetRegisterPlusOffset (dwarf_reg, offset); | 
| Caroline Tice | b9f76c3 | 2011-02-08 22:24:38 +0000 | [diff] [blame] | 3398 | if (wback && (n == 13)) // Pop Instruction | 
| Greg Clayton | 107e53d | 2011-07-06 04:07:21 +0000 | [diff] [blame] | 3399 | { | 
|  | 3400 | if (conditional) | 
|  | 3401 | context.type = EmulateInstruction::eContextRegisterLoad; | 
|  | 3402 | else | 
|  | 3403 | context.type = EmulateInstruction::eContextPopRegisterOffStack; | 
|  | 3404 | } | 
| Caroline Tice | b9f76c3 | 2011-02-08 22:24:38 +0000 | [diff] [blame] | 3405 |  | 
|  | 3406 | // R[i] = MemA [address, 4]; address = address + 4; | 
| Caroline Tice | cc96eb5 | 2011-02-17 19:20:40 +0000 | [diff] [blame] | 3407 | uint32_t data = MemARead (context, base_address + offset, addr_byte_size, 0, &success); | 
| Caroline Tice | b9f76c3 | 2011-02-08 22:24:38 +0000 | [diff] [blame] | 3408 | if (!success) | 
|  | 3409 | return false; | 
|  | 3410 |  | 
|  | 3411 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + i, data)) | 
|  | 3412 | return false; | 
|  | 3413 |  | 
|  | 3414 | offset += addr_byte_size; | 
|  | 3415 | } | 
|  | 3416 | } | 
|  | 3417 |  | 
|  | 3418 | if (BitIsSet (registers, 15)) | 
|  | 3419 | { | 
|  | 3420 | //LoadWritePC (MemA [address, 4]); | 
| Caroline Tice | 85aab33 | 2011-02-08 23:56:10 +0000 | [diff] [blame] | 3421 | context.type = EmulateInstruction::eContextRegisterPlusOffset; | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 3422 | context.SetRegisterPlusOffset (dwarf_reg, offset); | 
| Caroline Tice | cc96eb5 | 2011-02-17 19:20:40 +0000 | [diff] [blame] | 3423 | uint32_t data = MemARead (context, base_address + offset, addr_byte_size, 0, &success); | 
| Caroline Tice | b9f76c3 | 2011-02-08 22:24:38 +0000 | [diff] [blame] | 3424 | if (!success) | 
|  | 3425 | return false; | 
| Johnny Chen | e62b50d | 2011-02-09 22:02:17 +0000 | [diff] [blame] | 3426 | // In ARMv5T and above, this is an interworking branch. | 
| Johnny Chen | 668b451 | 2011-02-15 21:08:58 +0000 | [diff] [blame] | 3427 | if (!LoadWritePC(context, data)) | 
| Caroline Tice | b9f76c3 | 2011-02-08 22:24:38 +0000 | [diff] [blame] | 3428 | return false; | 
|  | 3429 | } | 
|  | 3430 |  | 
|  | 3431 | if (wback && BitIsClear (registers, n)) | 
|  | 3432 | { | 
| Caroline Tice | fa17220 | 2011-02-11 22:49:54 +0000 | [diff] [blame] | 3433 | // R[n] = R[n] + 4 * BitCount (registers) | 
|  | 3434 | int32_t offset = addr_byte_size * BitCount (registers); | 
|  | 3435 | context.type = EmulateInstruction::eContextAdjustBaseRegister; | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 3436 | context.SetRegisterPlusOffset (dwarf_reg, offset); | 
| Caroline Tice | b9f76c3 | 2011-02-08 22:24:38 +0000 | [diff] [blame] | 3437 |  | 
| Caroline Tice | b9f76c3 | 2011-02-08 22:24:38 +0000 | [diff] [blame] | 3438 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, base_address + offset)) | 
|  | 3439 | return false; | 
|  | 3440 | } | 
|  | 3441 | if (wback && BitIsSet (registers, n)) | 
|  | 3442 | // R[n] bits(32) UNKNOWN; | 
| Caroline Tice | 713c266 | 2011-02-11 17:59:55 +0000 | [diff] [blame] | 3443 | return WriteBits32Unknown (n); | 
| Caroline Tice | b9f76c3 | 2011-02-08 22:24:38 +0000 | [diff] [blame] | 3444 | } | 
|  | 3445 | return true; | 
|  | 3446 | } | 
| Caroline Tice | 713c266 | 2011-02-11 17:59:55 +0000 | [diff] [blame] | 3447 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3448 | // LDMDA loads multiple registers from consecutive memory locations using an address from a base register. | 
|  | 3449 | // The consecutive memory locations end at this address and the address just below the lowest of those locations | 
|  | 3450 | // can optionally be written back to the base register. | 
| Caroline Tice | 713c266 | 2011-02-11 17:59:55 +0000 | [diff] [blame] | 3451 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 3452 | EmulateInstructionARM::EmulateLDMDA (const uint32_t opcode, const ARMEncoding encoding) | 
| Caroline Tice | 713c266 | 2011-02-11 17:59:55 +0000 | [diff] [blame] | 3453 | { | 
|  | 3454 | #if 0 | 
|  | 3455 | // ARM pseudo code... | 
|  | 3456 | if ConditionPassed() then | 
|  | 3457 | EncodingSpecificOperations(); | 
|  | 3458 | address = R[n] - 4*BitCount(registers) + 4; | 
| Caroline Tice | b9f76c3 | 2011-02-08 22:24:38 +0000 | [diff] [blame] | 3459 |  | 
| Caroline Tice | 713c266 | 2011-02-11 17:59:55 +0000 | [diff] [blame] | 3460 | for i = 0 to 14 | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3461 | if registers<i> == '1' then | 
| Caroline Tice | 713c266 | 2011-02-11 17:59:55 +0000 | [diff] [blame] | 3462 | R[i] = MemA[address,4]; address = address + 4; | 
|  | 3463 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3464 | if registers<15> == '1' then | 
| Caroline Tice | 713c266 | 2011-02-11 17:59:55 +0000 | [diff] [blame] | 3465 | LoadWritePC(MemA[address,4]); | 
|  | 3466 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3467 | if wback && registers<n> == '0' then R[n] = R[n] - 4*BitCount(registers); | 
|  | 3468 | if wback && registers<n> == '1' then R[n] = bits(32) UNKNOWN; | 
| Caroline Tice | 713c266 | 2011-02-11 17:59:55 +0000 | [diff] [blame] | 3469 | #endif | 
|  | 3470 |  | 
|  | 3471 | bool success = false; | 
| Caroline Tice | 713c266 | 2011-02-11 17:59:55 +0000 | [diff] [blame] | 3472 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 3473 | if (ConditionPassed(opcode)) | 
| Caroline Tice | 713c266 | 2011-02-11 17:59:55 +0000 | [diff] [blame] | 3474 | { | 
|  | 3475 | uint32_t n; | 
|  | 3476 | uint32_t registers = 0; | 
|  | 3477 | bool wback; | 
|  | 3478 | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  | 3479 |  | 
|  | 3480 | // EncodingSpecificOperations(); | 
|  | 3481 | switch (encoding) | 
|  | 3482 | { | 
|  | 3483 | case eEncodingA1: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3484 | // n = UInt(Rn); registers = register_list; wback = (W == '1'); | 
| Caroline Tice | 713c266 | 2011-02-11 17:59:55 +0000 | [diff] [blame] | 3485 | n = Bits32 (opcode, 19, 16); | 
|  | 3486 | registers = Bits32 (opcode, 15, 0); | 
|  | 3487 | wback = BitIsSet (opcode, 21); | 
|  | 3488 |  | 
|  | 3489 | // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; | 
|  | 3490 | if ((n == 15) || (BitCount (registers) < 1)) | 
|  | 3491 | return false; | 
|  | 3492 |  | 
|  | 3493 | break; | 
|  | 3494 |  | 
|  | 3495 | default: | 
|  | 3496 | return false; | 
|  | 3497 | } | 
|  | 3498 | // address = R[n] - 4*BitCount(registers) + 4; | 
|  | 3499 |  | 
|  | 3500 | int32_t offset = 0; | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3501 | addr_t Rn = ReadCoreReg (n, &success); | 
| Caroline Tice | 713c266 | 2011-02-11 17:59:55 +0000 | [diff] [blame] | 3502 |  | 
|  | 3503 | if (!success) | 
|  | 3504 | return false; | 
|  | 3505 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3506 | addr_t address = Rn - (addr_byte_size * BitCount (registers)) + addr_byte_size; | 
| Caroline Tice | 713c266 | 2011-02-11 17:59:55 +0000 | [diff] [blame] | 3507 |  | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 3508 | EmulateInstruction::Context context; | 
|  | 3509 | context.type = EmulateInstruction::eContextRegisterPlusOffset; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 3510 | RegisterInfo dwarf_reg; | 
|  | 3511 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, dwarf_reg); | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 3512 | context.SetRegisterPlusOffset (dwarf_reg, offset); | 
| Caroline Tice | 713c266 | 2011-02-11 17:59:55 +0000 | [diff] [blame] | 3513 |  | 
|  | 3514 | // for i = 0 to 14 | 
|  | 3515 | for (int i = 0; i < 14; ++i) | 
|  | 3516 | { | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3517 | // if registers<i> == '1' then | 
| Caroline Tice | 713c266 | 2011-02-11 17:59:55 +0000 | [diff] [blame] | 3518 | if (BitIsSet (registers, i)) | 
|  | 3519 | { | 
|  | 3520 | // R[i] = MemA[address,4]; address = address + 4; | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3521 | context.SetRegisterPlusOffset (dwarf_reg, Rn - (address + offset)); | 
| Caroline Tice | cc96eb5 | 2011-02-17 19:20:40 +0000 | [diff] [blame] | 3522 | uint32_t data = MemARead (context, address + offset, addr_byte_size, 0, &success); | 
| Caroline Tice | 713c266 | 2011-02-11 17:59:55 +0000 | [diff] [blame] | 3523 | if (!success) | 
|  | 3524 | return false; | 
|  | 3525 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + i, data)) | 
|  | 3526 | return false; | 
|  | 3527 | offset += addr_byte_size; | 
|  | 3528 | } | 
|  | 3529 | } | 
|  | 3530 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3531 | // if registers<15> == '1' then | 
| Caroline Tice | 713c266 | 2011-02-11 17:59:55 +0000 | [diff] [blame] | 3532 | //     LoadWritePC(MemA[address,4]); | 
|  | 3533 | if (BitIsSet (registers, 15)) | 
|  | 3534 | { | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 3535 | context.SetRegisterPlusOffset (dwarf_reg, offset); | 
| Caroline Tice | cc96eb5 | 2011-02-17 19:20:40 +0000 | [diff] [blame] | 3536 | uint32_t data = MemARead (context, address + offset, addr_byte_size, 0, &success); | 
| Caroline Tice | 713c266 | 2011-02-11 17:59:55 +0000 | [diff] [blame] | 3537 | if (!success) | 
|  | 3538 | return false; | 
| Johnny Chen | 44c10f0 | 2011-02-11 19:37:03 +0000 | [diff] [blame] | 3539 | // In ARMv5T and above, this is an interworking branch. | 
| Johnny Chen | 668b451 | 2011-02-15 21:08:58 +0000 | [diff] [blame] | 3540 | if (!LoadWritePC(context, data)) | 
| Caroline Tice | 713c266 | 2011-02-11 17:59:55 +0000 | [diff] [blame] | 3541 | return false; | 
|  | 3542 | } | 
|  | 3543 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3544 | // if wback && registers<n> == '0' then R[n] = R[n] - 4*BitCount(registers); | 
| Caroline Tice | 713c266 | 2011-02-11 17:59:55 +0000 | [diff] [blame] | 3545 | if (wback && BitIsClear (registers, n)) | 
|  | 3546 | { | 
| Caroline Tice | 713c266 | 2011-02-11 17:59:55 +0000 | [diff] [blame] | 3547 | if (!success) | 
|  | 3548 | return false; | 
| Caroline Tice | fa17220 | 2011-02-11 22:49:54 +0000 | [diff] [blame] | 3549 |  | 
|  | 3550 | offset = (addr_byte_size * BitCount (registers)) * -1; | 
|  | 3551 | context.type = EmulateInstruction::eContextAdjustBaseRegister; | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 3552 | context.SetImmediateSigned (offset); | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3553 | addr_t addr = Rn + offset; | 
| Caroline Tice | 713c266 | 2011-02-11 17:59:55 +0000 | [diff] [blame] | 3554 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, addr)) | 
|  | 3555 | return false; | 
|  | 3556 | } | 
|  | 3557 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3558 | // if wback && registers<n> == '1' then R[n] = bits(32) UNKNOWN; | 
| Caroline Tice | 713c266 | 2011-02-11 17:59:55 +0000 | [diff] [blame] | 3559 | if (wback && BitIsSet (registers, n)) | 
|  | 3560 | return WriteBits32Unknown (n); | 
|  | 3561 | } | 
|  | 3562 | return true; | 
|  | 3563 | } | 
|  | 3564 |  | 
|  | 3565 | // LDMDB loads multiple registers from consecutive memory locations using an address from a base register.  The | 
|  | 3566 | // consecutive memory lcoations end just below this address, and the address of the lowest of those locations can | 
|  | 3567 | // be optionally written back to the base register. | 
| Caroline Tice | 0b29e24 | 2011-02-08 23:16:02 +0000 | [diff] [blame] | 3568 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 3569 | EmulateInstructionARM::EmulateLDMDB (const uint32_t opcode, const ARMEncoding encoding) | 
| Caroline Tice | 0b29e24 | 2011-02-08 23:16:02 +0000 | [diff] [blame] | 3570 | { | 
|  | 3571 | #if 0 | 
|  | 3572 | // ARM pseudo code... | 
|  | 3573 | if ConditionPassed() then | 
|  | 3574 | EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | 3575 | address = R[n] - 4*BitCount(registers); | 
|  | 3576 |  | 
|  | 3577 | for i = 0 to 14 | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3578 | if registers<i> == '1' then | 
| Caroline Tice | 0b29e24 | 2011-02-08 23:16:02 +0000 | [diff] [blame] | 3579 | R[i] = MemA[address,4]; address = address + 4; | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3580 | if registers<15> == '1' then | 
| Caroline Tice | 0b29e24 | 2011-02-08 23:16:02 +0000 | [diff] [blame] | 3581 | LoadWritePC(MemA[address,4]); | 
|  | 3582 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3583 | if wback && registers<n> == '0' then R[n] = R[n] - 4*BitCount(registers); | 
|  | 3584 | if wback && registers<n> == '1' then R[n] = bits(32) UNKNOWN; // Only possible for encoding A1 | 
| Caroline Tice | 0b29e24 | 2011-02-08 23:16:02 +0000 | [diff] [blame] | 3585 | #endif | 
|  | 3586 |  | 
|  | 3587 | bool success = false; | 
| Caroline Tice | 0b29e24 | 2011-02-08 23:16:02 +0000 | [diff] [blame] | 3588 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 3589 | if (ConditionPassed(opcode)) | 
| Caroline Tice | 0b29e24 | 2011-02-08 23:16:02 +0000 | [diff] [blame] | 3590 | { | 
|  | 3591 | uint32_t n; | 
|  | 3592 | uint32_t registers = 0; | 
|  | 3593 | bool wback; | 
|  | 3594 | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  | 3595 | switch (encoding) | 
|  | 3596 | { | 
|  | 3597 | case eEncodingT1: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3598 | // n = UInt(Rn); registers = P:M:'0':register_list; wback = (W == '1'); | 
| Caroline Tice | 0b29e24 | 2011-02-08 23:16:02 +0000 | [diff] [blame] | 3599 | n = Bits32 (opcode, 19, 16); | 
|  | 3600 | registers = Bits32 (opcode, 15, 0); | 
| Caroline Tice | b6f8d7e | 2011-02-15 18:10:01 +0000 | [diff] [blame] | 3601 | registers = registers & 0xdfff;  // Make sure bit 13 is a zero. | 
| Caroline Tice | 0b29e24 | 2011-02-08 23:16:02 +0000 | [diff] [blame] | 3602 | wback = BitIsSet (opcode, 21); | 
|  | 3603 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3604 | // if n == 15 || BitCount(registers) < 2 || (P == '1' && M == '1') then UNPREDICTABLE; | 
| Caroline Tice | 0b29e24 | 2011-02-08 23:16:02 +0000 | [diff] [blame] | 3605 | if ((n == 15) | 
|  | 3606 | || (BitCount (registers) < 2) | 
|  | 3607 | || (BitIsSet (opcode, 14) && BitIsSet (opcode, 15))) | 
|  | 3608 | return false; | 
|  | 3609 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3610 | // if registers<15> == '1' && InITBlock() && !LastInITBlock() then UNPREDICTABLE; | 
| Johnny Chen | 098ae2d | 2011-02-12 00:50:05 +0000 | [diff] [blame] | 3611 | if (BitIsSet (registers, 15) && InITBlock() && !LastInITBlock()) | 
| Caroline Tice | 0b29e24 | 2011-02-08 23:16:02 +0000 | [diff] [blame] | 3612 | return false; | 
|  | 3613 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3614 | // if wback && registers<n> == '1' then UNPREDICTABLE; | 
| Caroline Tice | 0b29e24 | 2011-02-08 23:16:02 +0000 | [diff] [blame] | 3615 | if (wback && BitIsSet (registers, n)) | 
|  | 3616 | return false; | 
|  | 3617 |  | 
|  | 3618 | break; | 
|  | 3619 |  | 
|  | 3620 | case eEncodingA1: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3621 | // n = UInt(Rn); registers = register_list; wback = (W == '1'); | 
| Caroline Tice | 0b29e24 | 2011-02-08 23:16:02 +0000 | [diff] [blame] | 3622 | n = Bits32 (opcode, 19, 16); | 
|  | 3623 | registers = Bits32 (opcode, 15, 0); | 
|  | 3624 | wback = BitIsSet (opcode, 21); | 
|  | 3625 |  | 
|  | 3626 | // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; | 
|  | 3627 | if ((n == 15) || (BitCount (registers) < 1)) | 
|  | 3628 | return false; | 
|  | 3629 |  | 
|  | 3630 | break; | 
|  | 3631 |  | 
|  | 3632 | default: | 
|  | 3633 | return false; | 
|  | 3634 | } | 
|  | 3635 |  | 
| Caroline Tice | 713c266 | 2011-02-11 17:59:55 +0000 | [diff] [blame] | 3636 | // address = R[n] - 4*BitCount(registers); | 
|  | 3637 |  | 
| Caroline Tice | 0b29e24 | 2011-02-08 23:16:02 +0000 | [diff] [blame] | 3638 | int32_t offset = 0; | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3639 | addr_t Rn = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success); | 
| Caroline Tice | 713c266 | 2011-02-11 17:59:55 +0000 | [diff] [blame] | 3640 |  | 
|  | 3641 | if (!success) | 
|  | 3642 | return false; | 
|  | 3643 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3644 | addr_t address = Rn - (addr_byte_size * BitCount (registers)); | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 3645 | EmulateInstruction::Context context; | 
|  | 3646 | context.type = EmulateInstruction::eContextRegisterPlusOffset; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 3647 | RegisterInfo dwarf_reg; | 
|  | 3648 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, dwarf_reg); | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3649 | context.SetRegisterPlusOffset (dwarf_reg, Rn - address); | 
| Caroline Tice | 0b29e24 | 2011-02-08 23:16:02 +0000 | [diff] [blame] | 3650 |  | 
|  | 3651 | for (int i = 0; i < 14; ++i) | 
|  | 3652 | { | 
|  | 3653 | if (BitIsSet (registers, i)) | 
|  | 3654 | { | 
|  | 3655 | // R[i] = MemA[address,4]; address = address + 4; | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3656 | context.SetRegisterPlusOffset (dwarf_reg, Rn - (address + offset)); | 
| Caroline Tice | cc96eb5 | 2011-02-17 19:20:40 +0000 | [diff] [blame] | 3657 | uint32_t data = MemARead (context, address + offset, addr_byte_size, 0, &success); | 
| Caroline Tice | 0b29e24 | 2011-02-08 23:16:02 +0000 | [diff] [blame] | 3658 | if (!success) | 
|  | 3659 | return false; | 
|  | 3660 |  | 
|  | 3661 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + i, data)) | 
|  | 3662 | return false; | 
|  | 3663 |  | 
|  | 3664 | offset += addr_byte_size; | 
|  | 3665 | } | 
|  | 3666 | } | 
|  | 3667 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3668 | // if registers<15> == '1' then | 
| Caroline Tice | 0b29e24 | 2011-02-08 23:16:02 +0000 | [diff] [blame] | 3669 | //     LoadWritePC(MemA[address,4]); | 
|  | 3670 | if (BitIsSet (registers, 15)) | 
|  | 3671 | { | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 3672 | context.SetRegisterPlusOffset (dwarf_reg, offset); | 
| Caroline Tice | cc96eb5 | 2011-02-17 19:20:40 +0000 | [diff] [blame] | 3673 | uint32_t data = MemARead (context, address + offset, addr_byte_size, 0, &success); | 
| Caroline Tice | 0b29e24 | 2011-02-08 23:16:02 +0000 | [diff] [blame] | 3674 | if (!success) | 
|  | 3675 | return false; | 
| Johnny Chen | e62b50d | 2011-02-09 22:02:17 +0000 | [diff] [blame] | 3676 | // In ARMv5T and above, this is an interworking branch. | 
| Johnny Chen | 668b451 | 2011-02-15 21:08:58 +0000 | [diff] [blame] | 3677 | if (!LoadWritePC(context, data)) | 
| Caroline Tice | 0b29e24 | 2011-02-08 23:16:02 +0000 | [diff] [blame] | 3678 | return false; | 
|  | 3679 | } | 
|  | 3680 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3681 | // if wback && registers<n> == '0' then R[n] = R[n] - 4*BitCount(registers); | 
| Caroline Tice | 0b29e24 | 2011-02-08 23:16:02 +0000 | [diff] [blame] | 3682 | if (wback && BitIsClear (registers, n)) | 
|  | 3683 | { | 
| Caroline Tice | 0b29e24 | 2011-02-08 23:16:02 +0000 | [diff] [blame] | 3684 | if (!success) | 
|  | 3685 | return false; | 
| Caroline Tice | fa17220 | 2011-02-11 22:49:54 +0000 | [diff] [blame] | 3686 |  | 
|  | 3687 | offset = (addr_byte_size * BitCount (registers)) * -1; | 
|  | 3688 | context.type = EmulateInstruction::eContextAdjustBaseRegister; | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 3689 | context.SetImmediateSigned (offset); | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3690 | addr_t addr = Rn + offset; | 
| Caroline Tice | 0b29e24 | 2011-02-08 23:16:02 +0000 | [diff] [blame] | 3691 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, addr)) | 
|  | 3692 | return false; | 
|  | 3693 | } | 
|  | 3694 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3695 | // if wback && registers<n> == '1' then R[n] = bits(32) UNKNOWN; // Only possible for encoding A1 | 
| Caroline Tice | 0b29e24 | 2011-02-08 23:16:02 +0000 | [diff] [blame] | 3696 | if (wback && BitIsSet (registers, n)) | 
| Caroline Tice | 713c266 | 2011-02-11 17:59:55 +0000 | [diff] [blame] | 3697 | return WriteBits32Unknown (n); | 
| Caroline Tice | 0b29e24 | 2011-02-08 23:16:02 +0000 | [diff] [blame] | 3698 | } | 
|  | 3699 | return true; | 
|  | 3700 | } | 
| Caroline Tice | 85aab33 | 2011-02-08 23:56:10 +0000 | [diff] [blame] | 3701 |  | 
| Caroline Tice | 713c266 | 2011-02-11 17:59:55 +0000 | [diff] [blame] | 3702 | // LDMIB loads multiple registers from consecutive memory locations using an address from a base register.  The | 
|  | 3703 | // consecutive memory locations start just above this address, and thea ddress of the last of those locations can | 
|  | 3704 | // optinoally be written back to the base register. | 
| Caroline Tice | 85aab33 | 2011-02-08 23:56:10 +0000 | [diff] [blame] | 3705 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 3706 | EmulateInstructionARM::EmulateLDMIB (const uint32_t opcode, const ARMEncoding encoding) | 
| Caroline Tice | 85aab33 | 2011-02-08 23:56:10 +0000 | [diff] [blame] | 3707 | { | 
|  | 3708 | #if 0 | 
|  | 3709 | if ConditionPassed() then | 
|  | 3710 | EncodingSpecificOperations(); | 
|  | 3711 | address = R[n] + 4; | 
|  | 3712 |  | 
|  | 3713 | for i = 0 to 14 | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3714 | if registers<i> == '1' then | 
| Caroline Tice | 85aab33 | 2011-02-08 23:56:10 +0000 | [diff] [blame] | 3715 | R[i] = MemA[address,4]; address = address + 4; | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3716 | if registers<15> == '1' then | 
| Caroline Tice | 85aab33 | 2011-02-08 23:56:10 +0000 | [diff] [blame] | 3717 | LoadWritePC(MemA[address,4]); | 
|  | 3718 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3719 | if wback && registers<n> == '0' then R[n] = R[n] + 4*BitCount(registers); | 
|  | 3720 | if wback && registers<n> == '1' then R[n] = bits(32) UNKNOWN; | 
| Caroline Tice | 85aab33 | 2011-02-08 23:56:10 +0000 | [diff] [blame] | 3721 | #endif | 
|  | 3722 |  | 
|  | 3723 | bool success = false; | 
| Caroline Tice | 85aab33 | 2011-02-08 23:56:10 +0000 | [diff] [blame] | 3724 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 3725 | if (ConditionPassed(opcode)) | 
| Caroline Tice | 85aab33 | 2011-02-08 23:56:10 +0000 | [diff] [blame] | 3726 | { | 
|  | 3727 | uint32_t n; | 
|  | 3728 | uint32_t registers = 0; | 
|  | 3729 | bool wback; | 
|  | 3730 | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  | 3731 | switch (encoding) | 
|  | 3732 | { | 
|  | 3733 | case eEncodingA1: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3734 | // n = UInt(Rn); registers = register_list; wback = (W == '1'); | 
| Caroline Tice | 85aab33 | 2011-02-08 23:56:10 +0000 | [diff] [blame] | 3735 | n = Bits32 (opcode, 19, 16); | 
|  | 3736 | registers = Bits32 (opcode, 15, 0); | 
|  | 3737 | wback = BitIsSet (opcode, 21); | 
|  | 3738 |  | 
|  | 3739 | // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; | 
|  | 3740 | if ((n == 15) || (BitCount (registers) < 1)) | 
|  | 3741 | return false; | 
|  | 3742 |  | 
|  | 3743 | break; | 
|  | 3744 | default: | 
|  | 3745 | return false; | 
|  | 3746 | } | 
|  | 3747 | // address = R[n] + 4; | 
|  | 3748 |  | 
|  | 3749 | int32_t offset = 0; | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3750 | addr_t Rn = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success); | 
| Caroline Tice | 713c266 | 2011-02-11 17:59:55 +0000 | [diff] [blame] | 3751 |  | 
|  | 3752 | if (!success) | 
|  | 3753 | return false; | 
|  | 3754 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3755 | addr_t address = Rn + addr_byte_size; | 
| Caroline Tice | 85aab33 | 2011-02-08 23:56:10 +0000 | [diff] [blame] | 3756 |  | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 3757 | EmulateInstruction::Context context; | 
|  | 3758 | context.type = EmulateInstruction::eContextRegisterPlusOffset; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 3759 | RegisterInfo dwarf_reg; | 
|  | 3760 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, dwarf_reg); | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 3761 | context.SetRegisterPlusOffset (dwarf_reg, offset); | 
| Caroline Tice | 85aab33 | 2011-02-08 23:56:10 +0000 | [diff] [blame] | 3762 |  | 
|  | 3763 | for (int i = 0; i < 14; ++i) | 
|  | 3764 | { | 
|  | 3765 | if (BitIsSet (registers, i)) | 
|  | 3766 | { | 
|  | 3767 | // R[i] = MemA[address,4]; address = address + 4; | 
|  | 3768 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3769 | context.SetRegisterPlusOffset (dwarf_reg, offset + addr_byte_size); | 
| Caroline Tice | cc96eb5 | 2011-02-17 19:20:40 +0000 | [diff] [blame] | 3770 | uint32_t data = MemARead (context, address + offset, addr_byte_size, 0, &success); | 
| Caroline Tice | 85aab33 | 2011-02-08 23:56:10 +0000 | [diff] [blame] | 3771 | if (!success) | 
|  | 3772 | return false; | 
|  | 3773 |  | 
|  | 3774 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + i, data)) | 
|  | 3775 | return false; | 
|  | 3776 |  | 
|  | 3777 | offset += addr_byte_size; | 
|  | 3778 | } | 
|  | 3779 | } | 
|  | 3780 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3781 | // if registers<15> == '1' then | 
| Caroline Tice | 85aab33 | 2011-02-08 23:56:10 +0000 | [diff] [blame] | 3782 | //     LoadWritePC(MemA[address,4]); | 
|  | 3783 | if (BitIsSet (registers, 15)) | 
|  | 3784 | { | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 3785 | context.SetRegisterPlusOffset (dwarf_reg, offset); | 
| Caroline Tice | cc96eb5 | 2011-02-17 19:20:40 +0000 | [diff] [blame] | 3786 | uint32_t data = MemARead (context, address + offset, addr_byte_size, 0, &success); | 
| Caroline Tice | 85aab33 | 2011-02-08 23:56:10 +0000 | [diff] [blame] | 3787 | if (!success) | 
|  | 3788 | return false; | 
| Johnny Chen | e62b50d | 2011-02-09 22:02:17 +0000 | [diff] [blame] | 3789 | // In ARMv5T and above, this is an interworking branch. | 
| Johnny Chen | 668b451 | 2011-02-15 21:08:58 +0000 | [diff] [blame] | 3790 | if (!LoadWritePC(context, data)) | 
| Caroline Tice | 85aab33 | 2011-02-08 23:56:10 +0000 | [diff] [blame] | 3791 | return false; | 
|  | 3792 | } | 
|  | 3793 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3794 | // if wback && registers<n> == '0' then R[n] = R[n] + 4*BitCount(registers); | 
| Caroline Tice | 85aab33 | 2011-02-08 23:56:10 +0000 | [diff] [blame] | 3795 | if (wback && BitIsClear (registers, n)) | 
|  | 3796 | { | 
| Caroline Tice | 85aab33 | 2011-02-08 23:56:10 +0000 | [diff] [blame] | 3797 | if (!success) | 
|  | 3798 | return false; | 
| Caroline Tice | fa17220 | 2011-02-11 22:49:54 +0000 | [diff] [blame] | 3799 |  | 
|  | 3800 | offset = addr_byte_size * BitCount (registers); | 
|  | 3801 | context.type = EmulateInstruction::eContextAdjustBaseRegister; | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 3802 | context.SetImmediateSigned (offset); | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3803 | addr_t addr = Rn + offset; | 
| Caroline Tice | 85aab33 | 2011-02-08 23:56:10 +0000 | [diff] [blame] | 3804 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, addr)) | 
|  | 3805 | return false; | 
|  | 3806 | } | 
|  | 3807 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3808 | // if wback && registers<n> == '1' then R[n] = bits(32) UNKNOWN; // Only possible for encoding A1 | 
| Caroline Tice | 85aab33 | 2011-02-08 23:56:10 +0000 | [diff] [blame] | 3809 | if (wback && BitIsSet (registers, n)) | 
| Caroline Tice | 713c266 | 2011-02-11 17:59:55 +0000 | [diff] [blame] | 3810 | return WriteBits32Unknown (n); | 
| Caroline Tice | 85aab33 | 2011-02-08 23:56:10 +0000 | [diff] [blame] | 3811 | } | 
|  | 3812 | return true; | 
|  | 3813 | } | 
| Caroline Tice | 0b29e24 | 2011-02-08 23:16:02 +0000 | [diff] [blame] | 3814 |  | 
| Johnny Chen | ef21b59 | 2011-02-10 01:52:38 +0000 | [diff] [blame] | 3815 | // Load Register (immediate) calculates an address from a base register value and | 
|  | 3816 | // an immediate offset, loads a word from memory, and writes to a register. | 
|  | 3817 | // LDR (immediate, Thumb) | 
|  | 3818 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 3819 | EmulateInstructionARM::EmulateLDRRtRnImm (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | ef21b59 | 2011-02-10 01:52:38 +0000 | [diff] [blame] | 3820 | { | 
|  | 3821 | #if 0 | 
|  | 3822 | // ARM pseudo code... | 
|  | 3823 | if (ConditionPassed()) | 
|  | 3824 | { | 
|  | 3825 | EncodingSpecificOperations(); NullCheckIfThumbEE(15); | 
|  | 3826 | offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | 3827 | address = if index then offset_addr else R[n]; | 
|  | 3828 | data = MemU[address,4]; | 
|  | 3829 | if wback then R[n] = offset_addr; | 
|  | 3830 | if t == 15 then | 
|  | 3831 | if address<1:0> == '00' then LoadWritePC(data); else UNPREDICTABLE; | 
|  | 3832 | elsif UnalignedSupport() || address<1:0> = '00' then | 
|  | 3833 | R[t] = data; | 
|  | 3834 | else R[t] = bits(32) UNKNOWN; // Can only apply before ARMv7 | 
|  | 3835 | } | 
|  | 3836 | #endif | 
|  | 3837 |  | 
|  | 3838 | bool success = false; | 
| Johnny Chen | ef21b59 | 2011-02-10 01:52:38 +0000 | [diff] [blame] | 3839 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 3840 | if (ConditionPassed(opcode)) | 
| Johnny Chen | ef21b59 | 2011-02-10 01:52:38 +0000 | [diff] [blame] | 3841 | { | 
|  | 3842 | uint32_t Rt; // the destination register | 
|  | 3843 | uint32_t Rn; // the base register | 
|  | 3844 | uint32_t imm32; // the immediate offset used to form the address | 
|  | 3845 | addr_t offset_addr; // the offset address | 
|  | 3846 | addr_t address; // the calculated address | 
|  | 3847 | uint32_t data; // the literal data value from memory load | 
|  | 3848 | bool add, index, wback; | 
|  | 3849 | switch (encoding) { | 
| Caroline Tice | baf1f64 | 2011-03-24 19:23:45 +0000 | [diff] [blame] | 3850 | case eEncodingT1: | 
| Caroline Tice | 55e569e | 2011-04-13 21:49:04 +0000 | [diff] [blame] | 3851 | Rt = Bits32(opcode, 2, 0); | 
|  | 3852 | Rn = Bits32(opcode, 5, 3); | 
| Caroline Tice | baf1f64 | 2011-03-24 19:23:45 +0000 | [diff] [blame] | 3853 | imm32 = Bits32(opcode, 10, 6) << 2; // imm32 = ZeroExtend(imm5:'00', 32); | 
|  | 3854 | // index = TRUE; add = TRUE; wback = FALSE | 
|  | 3855 | add = true; | 
|  | 3856 | index = true; | 
|  | 3857 | wback = false; | 
|  | 3858 |  | 
|  | 3859 | break; | 
|  | 3860 |  | 
|  | 3861 | case eEncodingT2: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3862 | // t = UInt(Rt); n = 13; imm32 = ZeroExtend(imm8:'00', 32); | 
| Caroline Tice | baf1f64 | 2011-03-24 19:23:45 +0000 | [diff] [blame] | 3863 | Rt = Bits32 (opcode, 10, 8); | 
|  | 3864 | Rn = 13; | 
|  | 3865 | imm32 = Bits32 (opcode, 7, 0) << 2; | 
|  | 3866 |  | 
|  | 3867 | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | 3868 | index = true; | 
|  | 3869 | add = true; | 
|  | 3870 | wback = false; | 
|  | 3871 |  | 
|  | 3872 | break; | 
|  | 3873 |  | 
|  | 3874 | case eEncodingT3: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3875 | // if Rn == '1111' then SEE LDR (literal); | 
| Caroline Tice | baf1f64 | 2011-03-24 19:23:45 +0000 | [diff] [blame] | 3876 | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32); | 
|  | 3877 | Rt = Bits32 (opcode, 15, 12); | 
|  | 3878 | Rn = Bits32 (opcode, 19, 16); | 
|  | 3879 | imm32 = Bits32 (opcode, 11, 0); | 
|  | 3880 |  | 
|  | 3881 | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | 3882 | index = true; | 
|  | 3883 | add = true; | 
|  | 3884 | wback = false; | 
|  | 3885 |  | 
|  | 3886 | // if t == 15 && InITBlock() && !LastInITBlock() then UNPREDICTABLE; | 
|  | 3887 | if ((Rt == 15) && InITBlock() && !LastInITBlock()) | 
|  | 3888 | return false; | 
|  | 3889 |  | 
|  | 3890 | break; | 
|  | 3891 |  | 
|  | 3892 | case eEncodingT4: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3893 | // if Rn == '1111' then SEE LDR (literal); | 
|  | 3894 | // if P == '1' && U == '1' && W == '0' then SEE LDRT; | 
|  | 3895 | // if Rn == '1101' && P == '0' && U == '1' && W == '1' && imm8 == '00000100' then SEE POP; | 
|  | 3896 | // if P == '0' && W == '0' then UNDEFINED; | 
| Caroline Tice | baf1f64 | 2011-03-24 19:23:45 +0000 | [diff] [blame] | 3897 | if (BitIsClear (opcode, 10) && BitIsClear (opcode, 8)) | 
|  | 3898 | return false; | 
|  | 3899 |  | 
|  | 3900 | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32); | 
|  | 3901 | Rt = Bits32 (opcode, 15, 12); | 
|  | 3902 | Rn = Bits32 (opcode, 19, 16); | 
|  | 3903 | imm32 = Bits32 (opcode, 7, 0); | 
|  | 3904 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3905 | // index = (P == '1'); add = (U == '1'); wback = (W == '1'); | 
| Caroline Tice | baf1f64 | 2011-03-24 19:23:45 +0000 | [diff] [blame] | 3906 | index = BitIsSet (opcode, 10); | 
|  | 3907 | add = BitIsSet (opcode, 9); | 
|  | 3908 | wback = BitIsSet (opcode, 8); | 
|  | 3909 |  | 
|  | 3910 | // if (wback && n == t) || (t == 15 && InITBlock() && !LastInITBlock()) then UNPREDICTABLE; | 
|  | 3911 | if ((wback && (Rn == Rt)) || ((Rt == 15) && InITBlock() && !LastInITBlock())) | 
|  | 3912 | return false; | 
|  | 3913 |  | 
|  | 3914 | break; | 
|  | 3915 |  | 
|  | 3916 | default: | 
|  | 3917 | return false; | 
| Johnny Chen | ef21b59 | 2011-02-10 01:52:38 +0000 | [diff] [blame] | 3918 | } | 
| Caroline Tice | baf1f64 | 2011-03-24 19:23:45 +0000 | [diff] [blame] | 3919 | uint32_t base = ReadCoreReg (Rn, &success); | 
| Johnny Chen | ef21b59 | 2011-02-10 01:52:38 +0000 | [diff] [blame] | 3920 | if (!success) | 
|  | 3921 | return false; | 
|  | 3922 | if (add) | 
|  | 3923 | offset_addr = base + imm32; | 
|  | 3924 | else | 
|  | 3925 | offset_addr = base - imm32; | 
|  | 3926 |  | 
|  | 3927 | address = (index ? offset_addr : base); | 
|  | 3928 |  | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 3929 | RegisterInfo base_reg; | 
|  | 3930 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + Rn, base_reg); | 
| Johnny Chen | ef21b59 | 2011-02-10 01:52:38 +0000 | [diff] [blame] | 3931 | if (wback) | 
|  | 3932 | { | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 3933 | EmulateInstruction::Context ctx; | 
| Caroline Tice | baf1f64 | 2011-03-24 19:23:45 +0000 | [diff] [blame] | 3934 | ctx.type = EmulateInstruction::eContextAdjustBaseRegister; | 
|  | 3935 | ctx.SetRegisterPlusOffset (base_reg, (int32_t) (offset_addr - base)); | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 3936 |  | 
| Johnny Chen | ef21b59 | 2011-02-10 01:52:38 +0000 | [diff] [blame] | 3937 | if (!WriteRegisterUnsigned (ctx, eRegisterKindDWARF, dwarf_r0 + Rn, offset_addr)) | 
|  | 3938 | return false; | 
|  | 3939 | } | 
|  | 3940 |  | 
|  | 3941 | // Prepare to write to the Rt register. | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 3942 | EmulateInstruction::Context context; | 
| Caroline Tice | baf1f64 | 2011-03-24 19:23:45 +0000 | [diff] [blame] | 3943 | context.type = EmulateInstruction::eContextRegisterLoad; | 
|  | 3944 | context.SetRegisterPlusOffset (base_reg, (int32_t) (offset_addr - base)); | 
| Johnny Chen | ef21b59 | 2011-02-10 01:52:38 +0000 | [diff] [blame] | 3945 |  | 
|  | 3946 | // Read memory from the address. | 
| Caroline Tice | cc96eb5 | 2011-02-17 19:20:40 +0000 | [diff] [blame] | 3947 | data = MemURead(context, address, 4, 0, &success); | 
| Johnny Chen | ef21b59 | 2011-02-10 01:52:38 +0000 | [diff] [blame] | 3948 | if (!success) | 
|  | 3949 | return false; | 
| Johnny Chen | ef21b59 | 2011-02-10 01:52:38 +0000 | [diff] [blame] | 3950 |  | 
|  | 3951 | if (Rt == 15) | 
|  | 3952 | { | 
|  | 3953 | if (Bits32(address, 1, 0) == 0) | 
|  | 3954 | { | 
| Johnny Chen | 668b451 | 2011-02-15 21:08:58 +0000 | [diff] [blame] | 3955 | if (!LoadWritePC(context, data)) | 
| Johnny Chen | ef21b59 | 2011-02-10 01:52:38 +0000 | [diff] [blame] | 3956 | return false; | 
|  | 3957 | } | 
|  | 3958 | else | 
|  | 3959 | return false; | 
|  | 3960 | } | 
|  | 3961 | else if (UnalignedSupport() || Bits32(address, 1, 0) == 0) | 
|  | 3962 | { | 
|  | 3963 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rt, data)) | 
|  | 3964 | return false; | 
|  | 3965 | } | 
|  | 3966 | else | 
| Caroline Tice | baf1f64 | 2011-03-24 19:23:45 +0000 | [diff] [blame] | 3967 | WriteBits32Unknown (Rt); | 
| Johnny Chen | ef21b59 | 2011-02-10 01:52:38 +0000 | [diff] [blame] | 3968 | } | 
|  | 3969 | return true; | 
|  | 3970 | } | 
|  | 3971 |  | 
| Caroline Tice | af55656 | 2011-02-15 18:42:15 +0000 | [diff] [blame] | 3972 | // STM (Store Multiple Increment After) stores multiple registers to consecutive memory locations using an address | 
|  | 3973 | // from a base register.  The consecutive memory locations start at this address, and teh address just above the last | 
|  | 3974 | // of those locations can optionally be written back to the base register. | 
| Caroline Tice | fa17220 | 2011-02-11 22:49:54 +0000 | [diff] [blame] | 3975 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 3976 | EmulateInstructionARM::EmulateSTM (const uint32_t opcode, const ARMEncoding encoding) | 
| Caroline Tice | fa17220 | 2011-02-11 22:49:54 +0000 | [diff] [blame] | 3977 | { | 
|  | 3978 | #if 0 | 
|  | 3979 | if ConditionPassed() then | 
|  | 3980 | EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | 3981 | address = R[n]; | 
|  | 3982 |  | 
|  | 3983 | for i = 0 to 14 | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3984 | if registers<i> == '1' then | 
| Caroline Tice | fa17220 | 2011-02-11 22:49:54 +0000 | [diff] [blame] | 3985 | if i == n && wback && i != LowestSetBit(registers) then | 
|  | 3986 | MemA[address,4] = bits(32) UNKNOWN; // Only possible for encodings T1 and A1 | 
|  | 3987 | else | 
|  | 3988 | MemA[address,4] = R[i]; | 
|  | 3989 | address = address + 4; | 
|  | 3990 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 3991 | if registers<15> == '1' then // Only possible for encoding A1 | 
| Caroline Tice | fa17220 | 2011-02-11 22:49:54 +0000 | [diff] [blame] | 3992 | MemA[address,4] = PCStoreValue(); | 
|  | 3993 | if wback then R[n] = R[n] + 4*BitCount(registers); | 
|  | 3994 | #endif | 
|  | 3995 |  | 
|  | 3996 | bool success = false; | 
| Caroline Tice | fa17220 | 2011-02-11 22:49:54 +0000 | [diff] [blame] | 3997 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 3998 | if (ConditionPassed(opcode)) | 
| Caroline Tice | fa17220 | 2011-02-11 22:49:54 +0000 | [diff] [blame] | 3999 | { | 
|  | 4000 | uint32_t n; | 
|  | 4001 | uint32_t registers = 0; | 
|  | 4002 | bool wback; | 
|  | 4003 | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  | 4004 |  | 
|  | 4005 | // EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | 4006 | switch (encoding) | 
|  | 4007 | { | 
|  | 4008 | case eEncodingT1: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4009 | // n = UInt(Rn); registers = '00000000':register_list; wback = TRUE; | 
| Caroline Tice | fa17220 | 2011-02-11 22:49:54 +0000 | [diff] [blame] | 4010 | n = Bits32 (opcode, 10, 8); | 
|  | 4011 | registers = Bits32 (opcode, 7, 0); | 
| Caroline Tice | b6f8d7e | 2011-02-15 18:10:01 +0000 | [diff] [blame] | 4012 | registers = registers & 0x00ff;  // Make sure the top 8 bits are zeros. | 
| Caroline Tice | fa17220 | 2011-02-11 22:49:54 +0000 | [diff] [blame] | 4013 | wback = true; | 
|  | 4014 |  | 
|  | 4015 | // if BitCount(registers) < 1 then UNPREDICTABLE; | 
|  | 4016 | if (BitCount (registers) < 1) | 
|  | 4017 | return false; | 
|  | 4018 |  | 
|  | 4019 | break; | 
|  | 4020 |  | 
|  | 4021 | case eEncodingT2: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4022 | // n = UInt(Rn); registers = '0':M:'0':register_list; wback = (W == '1'); | 
| Caroline Tice | fa17220 | 2011-02-11 22:49:54 +0000 | [diff] [blame] | 4023 | n = Bits32 (opcode, 19, 16); | 
|  | 4024 | registers = Bits32 (opcode, 15, 0); | 
| Caroline Tice | b6f8d7e | 2011-02-15 18:10:01 +0000 | [diff] [blame] | 4025 | registers = registers & 0x5fff; // Make sure bits 15 & 13 are zeros. | 
| Caroline Tice | fa17220 | 2011-02-11 22:49:54 +0000 | [diff] [blame] | 4026 | wback = BitIsSet (opcode, 21); | 
|  | 4027 |  | 
|  | 4028 | // if n == 15 || BitCount(registers) < 2 then UNPREDICTABLE; | 
|  | 4029 | if ((n == 15) || (BitCount (registers) < 2)) | 
|  | 4030 | return false; | 
|  | 4031 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4032 | // if wback && registers<n> == '1' then UNPREDICTABLE; | 
| Caroline Tice | fa17220 | 2011-02-11 22:49:54 +0000 | [diff] [blame] | 4033 | if (wback && BitIsSet (registers, n)) | 
|  | 4034 | return false; | 
|  | 4035 |  | 
|  | 4036 | break; | 
|  | 4037 |  | 
|  | 4038 | case eEncodingA1: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4039 | // n = UInt(Rn); registers = register_list; wback = (W == '1'); | 
| Caroline Tice | fa17220 | 2011-02-11 22:49:54 +0000 | [diff] [blame] | 4040 | n = Bits32 (opcode, 19, 16); | 
|  | 4041 | registers = Bits32 (opcode, 15, 0); | 
|  | 4042 | wback = BitIsSet (opcode, 21); | 
|  | 4043 |  | 
|  | 4044 | // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; | 
|  | 4045 | if ((n == 15) || (BitCount (registers) < 1)) | 
|  | 4046 | return false; | 
|  | 4047 |  | 
|  | 4048 | break; | 
|  | 4049 |  | 
|  | 4050 | default: | 
|  | 4051 | return false; | 
|  | 4052 | } | 
|  | 4053 |  | 
|  | 4054 | // address = R[n]; | 
|  | 4055 | int32_t offset = 0; | 
|  | 4056 | const addr_t address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success); | 
|  | 4057 | if (!success) | 
|  | 4058 | return false; | 
|  | 4059 |  | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 4060 | EmulateInstruction::Context context; | 
|  | 4061 | context.type = EmulateInstruction::eContextRegisterStore; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 4062 | RegisterInfo base_reg; | 
|  | 4063 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
| Caroline Tice | fa17220 | 2011-02-11 22:49:54 +0000 | [diff] [blame] | 4064 |  | 
|  | 4065 | // for i = 0 to 14 | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4066 | int lowest_set_bit = 14; | 
| Caroline Tice | fa17220 | 2011-02-11 22:49:54 +0000 | [diff] [blame] | 4067 | for (int i = 0; i < 14; ++i) | 
|  | 4068 | { | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4069 | // if registers<i> == '1' then | 
| Caroline Tice | fa17220 | 2011-02-11 22:49:54 +0000 | [diff] [blame] | 4070 | if (BitIsSet (registers, i)) | 
|  | 4071 | { | 
|  | 4072 | if (i < lowest_set_bit) | 
|  | 4073 | lowest_set_bit = i; | 
|  | 4074 | // if i == n && wback && i != LowestSetBit(registers) then | 
|  | 4075 | if ((i == n) && wback && (i != lowest_set_bit)) | 
|  | 4076 | // MemA[address,4] = bits(32) UNKNOWN; // Only possible for encodings T1 and A1 | 
|  | 4077 | WriteBits32UnknownToMemory (address + offset); | 
|  | 4078 | else | 
|  | 4079 | { | 
|  | 4080 | // MemA[address,4] = R[i]; | 
|  | 4081 | uint32_t data = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + i, 0, &success); | 
|  | 4082 | if (!success) | 
|  | 4083 | return false; | 
|  | 4084 |  | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 4085 | RegisterInfo data_reg; | 
|  | 4086 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + i, data_reg); | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 4087 | context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, offset); | 
| Caroline Tice | cc96eb5 | 2011-02-17 19:20:40 +0000 | [diff] [blame] | 4088 | if (!MemAWrite (context, address + offset, data, addr_byte_size)) | 
| Caroline Tice | fa17220 | 2011-02-11 22:49:54 +0000 | [diff] [blame] | 4089 | return false; | 
|  | 4090 | } | 
|  | 4091 |  | 
|  | 4092 | // address = address + 4; | 
|  | 4093 | offset += addr_byte_size; | 
|  | 4094 | } | 
|  | 4095 | } | 
|  | 4096 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4097 | // if registers<15> == '1' then // Only possible for encoding A1 | 
| Caroline Tice | fa17220 | 2011-02-11 22:49:54 +0000 | [diff] [blame] | 4098 | //     MemA[address,4] = PCStoreValue(); | 
|  | 4099 | if (BitIsSet (registers, 15)) | 
|  | 4100 | { | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 4101 | RegisterInfo pc_reg; | 
|  | 4102 | GetRegisterInfo (eRegisterKindDWARF, dwarf_pc, pc_reg); | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 4103 | context.SetRegisterPlusOffset (pc_reg, 8); | 
| Caroline Tice | 8d681f5 | 2011-03-17 23:50:16 +0000 | [diff] [blame] | 4104 | const uint32_t pc = ReadCoreReg (PC_REG, &success); | 
| Caroline Tice | fa17220 | 2011-02-11 22:49:54 +0000 | [diff] [blame] | 4105 | if (!success) | 
|  | 4106 | return false; | 
|  | 4107 |  | 
| Caroline Tice | 8d681f5 | 2011-03-17 23:50:16 +0000 | [diff] [blame] | 4108 | if (!MemAWrite (context, address + offset, pc, addr_byte_size)) | 
| Caroline Tice | fa17220 | 2011-02-11 22:49:54 +0000 | [diff] [blame] | 4109 | return false; | 
|  | 4110 | } | 
|  | 4111 |  | 
|  | 4112 | // if wback then R[n] = R[n] + 4*BitCount(registers); | 
|  | 4113 | if (wback) | 
|  | 4114 | { | 
|  | 4115 | offset = addr_byte_size * BitCount (registers); | 
|  | 4116 | context.type = EmulateInstruction::eContextAdjustBaseRegister; | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 4117 | context.SetImmediateSigned (offset); | 
| Caroline Tice | fa17220 | 2011-02-11 22:49:54 +0000 | [diff] [blame] | 4118 | addr_t data = address + offset; | 
|  | 4119 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, data)) | 
|  | 4120 | return false; | 
|  | 4121 | } | 
|  | 4122 | } | 
|  | 4123 | return true; | 
|  | 4124 | } | 
|  | 4125 |  | 
| Caroline Tice | af55656 | 2011-02-15 18:42:15 +0000 | [diff] [blame] | 4126 | // STMDA (Store Multiple Decrement After) stores multiple registers to consecutive memory locations using an address | 
|  | 4127 | // from a base register.  The consecutive memory locations end at this address, and the address just below the lowest | 
|  | 4128 | // of those locations can optionally be written back to the base register. | 
| Caroline Tice | 1511f50 | 2011-02-15 00:19:42 +0000 | [diff] [blame] | 4129 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 4130 | EmulateInstructionARM::EmulateSTMDA (const uint32_t opcode, const ARMEncoding encoding) | 
| Caroline Tice | 1511f50 | 2011-02-15 00:19:42 +0000 | [diff] [blame] | 4131 | { | 
|  | 4132 | #if 0 | 
|  | 4133 | if ConditionPassed() then | 
|  | 4134 | EncodingSpecificOperations(); | 
|  | 4135 | address = R[n] - 4*BitCount(registers) + 4; | 
|  | 4136 |  | 
|  | 4137 | for i = 0 to 14 | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4138 | if registers<i> == '1' then | 
| Caroline Tice | 1511f50 | 2011-02-15 00:19:42 +0000 | [diff] [blame] | 4139 | if i == n && wback && i != LowestSetBit(registers) then | 
|  | 4140 | MemA[address,4] = bits(32) UNKNOWN; | 
|  | 4141 | else | 
|  | 4142 | MemA[address,4] = R[i]; | 
|  | 4143 | address = address + 4; | 
|  | 4144 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4145 | if registers<15> == '1' then | 
| Caroline Tice | 1511f50 | 2011-02-15 00:19:42 +0000 | [diff] [blame] | 4146 | MemA[address,4] = PCStoreValue(); | 
|  | 4147 |  | 
|  | 4148 | if wback then R[n] = R[n] - 4*BitCount(registers); | 
|  | 4149 | #endif | 
|  | 4150 |  | 
|  | 4151 | bool success = false; | 
| Caroline Tice | 1511f50 | 2011-02-15 00:19:42 +0000 | [diff] [blame] | 4152 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 4153 | if (ConditionPassed(opcode)) | 
| Caroline Tice | 1511f50 | 2011-02-15 00:19:42 +0000 | [diff] [blame] | 4154 | { | 
|  | 4155 | uint32_t n; | 
|  | 4156 | uint32_t registers = 0; | 
|  | 4157 | bool wback; | 
|  | 4158 | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  | 4159 |  | 
|  | 4160 | // EncodingSpecificOperations(); | 
|  | 4161 | switch (encoding) | 
|  | 4162 | { | 
|  | 4163 | case eEncodingA1: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4164 | // n = UInt(Rn); registers = register_list; wback = (W == '1'); | 
| Caroline Tice | 1511f50 | 2011-02-15 00:19:42 +0000 | [diff] [blame] | 4165 | n = Bits32 (opcode, 19, 16); | 
|  | 4166 | registers = Bits32 (opcode, 15, 0); | 
|  | 4167 | wback = BitIsSet (opcode, 21); | 
|  | 4168 |  | 
|  | 4169 | // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; | 
|  | 4170 | if ((n == 15) || (BitCount (registers) < 1)) | 
|  | 4171 | return false; | 
|  | 4172 | break; | 
|  | 4173 | default: | 
|  | 4174 | return false; | 
|  | 4175 | } | 
|  | 4176 |  | 
|  | 4177 | // address = R[n] - 4*BitCount(registers) + 4; | 
|  | 4178 | int32_t offset = 0; | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4179 | addr_t Rn = ReadCoreReg (n, &success); | 
| Caroline Tice | 1511f50 | 2011-02-15 00:19:42 +0000 | [diff] [blame] | 4180 | if (!success) | 
|  | 4181 | return false; | 
|  | 4182 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4183 | addr_t address = Rn - (addr_byte_size * BitCount (registers)) + 4; | 
| Caroline Tice | 1511f50 | 2011-02-15 00:19:42 +0000 | [diff] [blame] | 4184 |  | 
|  | 4185 | EmulateInstruction::Context context; | 
|  | 4186 | context.type = EmulateInstruction::eContextRegisterStore; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 4187 | RegisterInfo base_reg; | 
|  | 4188 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
| Caroline Tice | 1511f50 | 2011-02-15 00:19:42 +0000 | [diff] [blame] | 4189 |  | 
|  | 4190 | // for i = 0 to 14 | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4191 | int lowest_bit_set = 14; | 
| Caroline Tice | 1511f50 | 2011-02-15 00:19:42 +0000 | [diff] [blame] | 4192 | for (int i = 0; i < 14; ++i) | 
|  | 4193 | { | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4194 | // if registers<i> == '1' then | 
| Caroline Tice | 1511f50 | 2011-02-15 00:19:42 +0000 | [diff] [blame] | 4195 | if (BitIsSet (registers, i)) | 
|  | 4196 | { | 
|  | 4197 | if (i < lowest_bit_set) | 
|  | 4198 | lowest_bit_set = i; | 
|  | 4199 | //if i == n && wback && i != LowestSetBit(registers) then | 
|  | 4200 | if ((i == n) && wback && (i != lowest_bit_set)) | 
|  | 4201 | // MemA[address,4] = bits(32) UNKNOWN; | 
|  | 4202 | WriteBits32UnknownToMemory (address + offset); | 
|  | 4203 | else | 
|  | 4204 | { | 
|  | 4205 | // MemA[address,4] = R[i]; | 
|  | 4206 | uint32_t data = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + i, 0, &success); | 
|  | 4207 | if (!success) | 
|  | 4208 | return false; | 
|  | 4209 |  | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 4210 | RegisterInfo data_reg; | 
|  | 4211 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + i, data_reg); | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4212 | context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, Rn - (address + offset)); | 
| Caroline Tice | cc96eb5 | 2011-02-17 19:20:40 +0000 | [diff] [blame] | 4213 | if (!MemAWrite (context, address + offset, data, addr_byte_size)) | 
| Caroline Tice | 1511f50 | 2011-02-15 00:19:42 +0000 | [diff] [blame] | 4214 | return false; | 
|  | 4215 | } | 
|  | 4216 |  | 
|  | 4217 | // address = address + 4; | 
|  | 4218 | offset += addr_byte_size; | 
|  | 4219 | } | 
|  | 4220 | } | 
|  | 4221 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4222 | // if registers<15> == '1' then | 
| Caroline Tice | 1511f50 | 2011-02-15 00:19:42 +0000 | [diff] [blame] | 4223 | //    MemA[address,4] = PCStoreValue(); | 
|  | 4224 | if (BitIsSet (registers, 15)) | 
|  | 4225 | { | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 4226 | RegisterInfo pc_reg; | 
|  | 4227 | GetRegisterInfo (eRegisterKindDWARF, dwarf_pc, pc_reg); | 
| Caroline Tice | 1511f50 | 2011-02-15 00:19:42 +0000 | [diff] [blame] | 4228 | context.SetRegisterPlusOffset (pc_reg, 8); | 
| Caroline Tice | 8d681f5 | 2011-03-17 23:50:16 +0000 | [diff] [blame] | 4229 | const uint32_t pc = ReadCoreReg (PC_REG, &success); | 
| Caroline Tice | 1511f50 | 2011-02-15 00:19:42 +0000 | [diff] [blame] | 4230 | if (!success) | 
|  | 4231 | return false; | 
|  | 4232 |  | 
| Caroline Tice | 8d681f5 | 2011-03-17 23:50:16 +0000 | [diff] [blame] | 4233 | if (!MemAWrite (context, address + offset, pc, addr_byte_size)) | 
| Caroline Tice | 1511f50 | 2011-02-15 00:19:42 +0000 | [diff] [blame] | 4234 | return false; | 
|  | 4235 | } | 
|  | 4236 |  | 
|  | 4237 | // if wback then R[n] = R[n] - 4*BitCount(registers); | 
|  | 4238 | if (wback) | 
|  | 4239 | { | 
| Caroline Tice | af55656 | 2011-02-15 18:42:15 +0000 | [diff] [blame] | 4240 | offset = (addr_byte_size * BitCount (registers)) * -1; | 
| Caroline Tice | 1511f50 | 2011-02-15 00:19:42 +0000 | [diff] [blame] | 4241 | context.type = EmulateInstruction::eContextAdjustBaseRegister; | 
|  | 4242 | context.SetImmediateSigned (offset); | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4243 | addr_t data = Rn + offset; | 
| Caroline Tice | 1511f50 | 2011-02-15 00:19:42 +0000 | [diff] [blame] | 4244 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, data)) | 
|  | 4245 | return false; | 
|  | 4246 | } | 
|  | 4247 | } | 
|  | 4248 | return true; | 
|  | 4249 | } | 
|  | 4250 |  | 
| Caroline Tice | af55656 | 2011-02-15 18:42:15 +0000 | [diff] [blame] | 4251 | // STMDB (Store Multiple Decrement Before) stores multiple registers to consecutive memory locations using an address | 
|  | 4252 | // from a base register.  The consecutive memory locations end just below this address, and the address of the first of | 
|  | 4253 | // those locations can optionally be written back to the base register. | 
| Caroline Tice | b6f8d7e | 2011-02-15 18:10:01 +0000 | [diff] [blame] | 4254 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 4255 | EmulateInstructionARM::EmulateSTMDB (const uint32_t opcode, const ARMEncoding encoding) | 
| Caroline Tice | b6f8d7e | 2011-02-15 18:10:01 +0000 | [diff] [blame] | 4256 | { | 
|  | 4257 | #if 0 | 
|  | 4258 | if ConditionPassed() then | 
|  | 4259 | EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | 4260 | address = R[n] - 4*BitCount(registers); | 
|  | 4261 |  | 
|  | 4262 | for i = 0 to 14 | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4263 | if registers<i> == '1' then | 
| Caroline Tice | b6f8d7e | 2011-02-15 18:10:01 +0000 | [diff] [blame] | 4264 | if i == n && wback && i != LowestSetBit(registers) then | 
|  | 4265 | MemA[address,4] = bits(32) UNKNOWN; // Only possible for encoding A1 | 
|  | 4266 | else | 
|  | 4267 | MemA[address,4] = R[i]; | 
|  | 4268 | address = address + 4; | 
|  | 4269 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4270 | if registers<15> == '1' then // Only possible for encoding A1 | 
| Caroline Tice | b6f8d7e | 2011-02-15 18:10:01 +0000 | [diff] [blame] | 4271 | MemA[address,4] = PCStoreValue(); | 
|  | 4272 |  | 
|  | 4273 | if wback then R[n] = R[n] - 4*BitCount(registers); | 
|  | 4274 | #endif | 
|  | 4275 |  | 
|  | 4276 |  | 
|  | 4277 | bool success = false; | 
| Caroline Tice | b6f8d7e | 2011-02-15 18:10:01 +0000 | [diff] [blame] | 4278 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 4279 | if (ConditionPassed(opcode)) | 
| Caroline Tice | b6f8d7e | 2011-02-15 18:10:01 +0000 | [diff] [blame] | 4280 | { | 
|  | 4281 | uint32_t n; | 
|  | 4282 | uint32_t registers = 0; | 
|  | 4283 | bool wback; | 
|  | 4284 | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  | 4285 |  | 
|  | 4286 | // EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | 4287 | switch (encoding) | 
|  | 4288 | { | 
|  | 4289 | case eEncodingT1: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4290 | // if W == '1' && Rn == '1101' then SEE PUSH; | 
| Caroline Tice | b6f8d7e | 2011-02-15 18:10:01 +0000 | [diff] [blame] | 4291 | if ((BitIsSet (opcode, 21)) && (Bits32 (opcode, 19, 16) == 13)) | 
|  | 4292 | { | 
|  | 4293 | // See PUSH | 
|  | 4294 | } | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4295 | // n = UInt(Rn); registers = '0':M:'0':register_list; wback = (W == '1'); | 
| Caroline Tice | b6f8d7e | 2011-02-15 18:10:01 +0000 | [diff] [blame] | 4296 | n = Bits32 (opcode, 19, 16); | 
|  | 4297 | registers = Bits32 (opcode, 15, 0); | 
|  | 4298 | registers = registers & 0x5fff;  // Make sure bits 15 & 13 are zeros. | 
|  | 4299 | wback = BitIsSet (opcode, 21); | 
|  | 4300 | // if n == 15 || BitCount(registers) < 2 then UNPREDICTABLE; | 
|  | 4301 | if ((n == 15) || BitCount (registers) < 2) | 
|  | 4302 | return false; | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4303 | // if wback && registers<n> == '1' then UNPREDICTABLE; | 
| Caroline Tice | b6f8d7e | 2011-02-15 18:10:01 +0000 | [diff] [blame] | 4304 | if (wback && BitIsSet (registers, n)) | 
|  | 4305 | return false; | 
|  | 4306 | break; | 
|  | 4307 |  | 
|  | 4308 | case eEncodingA1: | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 4309 | // if W == '1' && Rn == '1101Õ && BitCount(register_list) >= 2 then SEE PUSH; | 
| Caroline Tice | b6f8d7e | 2011-02-15 18:10:01 +0000 | [diff] [blame] | 4310 | if (BitIsSet (opcode, 21) && (Bits32 (opcode, 19, 16) == 13) && BitCount (Bits32 (opcode, 15, 0)) >= 2) | 
|  | 4311 | { | 
|  | 4312 | // See Push | 
|  | 4313 | } | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4314 | // n = UInt(Rn); registers = register_list; wback = (W == '1'); | 
| Caroline Tice | b6f8d7e | 2011-02-15 18:10:01 +0000 | [diff] [blame] | 4315 | n = Bits32 (opcode, 19, 16); | 
|  | 4316 | registers = Bits32 (opcode, 15, 0); | 
|  | 4317 | wback = BitIsSet (opcode, 21); | 
|  | 4318 | // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; | 
|  | 4319 | if ((n == 15) || BitCount (registers) < 1) | 
|  | 4320 | return false; | 
|  | 4321 | break; | 
|  | 4322 |  | 
|  | 4323 | default: | 
|  | 4324 | return false; | 
|  | 4325 | } | 
|  | 4326 |  | 
|  | 4327 | // address = R[n] - 4*BitCount(registers); | 
|  | 4328 |  | 
|  | 4329 | int32_t offset = 0; | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4330 | addr_t Rn = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success); | 
| Caroline Tice | b6f8d7e | 2011-02-15 18:10:01 +0000 | [diff] [blame] | 4331 | if (!success) | 
|  | 4332 | return false; | 
|  | 4333 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4334 | addr_t address = Rn - (addr_byte_size * BitCount (registers)); | 
| Caroline Tice | b6f8d7e | 2011-02-15 18:10:01 +0000 | [diff] [blame] | 4335 |  | 
|  | 4336 | EmulateInstruction::Context context; | 
|  | 4337 | context.type = EmulateInstruction::eContextRegisterStore; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 4338 | RegisterInfo base_reg; | 
|  | 4339 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
| Caroline Tice | b6f8d7e | 2011-02-15 18:10:01 +0000 | [diff] [blame] | 4340 |  | 
|  | 4341 | // for i = 0 to 14 | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4342 | uint32_t lowest_set_bit = 14; | 
| Caroline Tice | b6f8d7e | 2011-02-15 18:10:01 +0000 | [diff] [blame] | 4343 | for (int i = 0; i < 14; ++i) | 
|  | 4344 | { | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4345 | // if registers<i> == '1' then | 
| Caroline Tice | b6f8d7e | 2011-02-15 18:10:01 +0000 | [diff] [blame] | 4346 | if (BitIsSet (registers, i)) | 
|  | 4347 | { | 
|  | 4348 | if (i < lowest_set_bit) | 
|  | 4349 | lowest_set_bit = i; | 
|  | 4350 | // if i == n && wback && i != LowestSetBit(registers) then | 
|  | 4351 | if ((i == n) && wback && (i != lowest_set_bit)) | 
|  | 4352 | // MemA[address,4] = bits(32) UNKNOWN; // Only possible for encoding A1 | 
|  | 4353 | WriteBits32UnknownToMemory (address + offset); | 
|  | 4354 | else | 
|  | 4355 | { | 
|  | 4356 | // MemA[address,4] = R[i]; | 
|  | 4357 | uint32_t data = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + i, 0, &success); | 
|  | 4358 | if (!success) | 
|  | 4359 | return false; | 
|  | 4360 |  | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 4361 | RegisterInfo data_reg; | 
|  | 4362 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + i, data_reg); | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4363 | context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, Rn - (address + offset)); | 
| Caroline Tice | cc96eb5 | 2011-02-17 19:20:40 +0000 | [diff] [blame] | 4364 | if (!MemAWrite (context, address + offset, data, addr_byte_size)) | 
| Caroline Tice | b6f8d7e | 2011-02-15 18:10:01 +0000 | [diff] [blame] | 4365 | return false; | 
|  | 4366 | } | 
|  | 4367 |  | 
|  | 4368 | // address = address + 4; | 
|  | 4369 | offset += addr_byte_size; | 
|  | 4370 | } | 
|  | 4371 | } | 
|  | 4372 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4373 | // if registers<15> == '1' then // Only possible for encoding A1 | 
| Caroline Tice | b6f8d7e | 2011-02-15 18:10:01 +0000 | [diff] [blame] | 4374 | //     MemA[address,4] = PCStoreValue(); | 
|  | 4375 | if (BitIsSet (registers, 15)) | 
|  | 4376 | { | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 4377 | RegisterInfo pc_reg; | 
|  | 4378 | GetRegisterInfo (eRegisterKindDWARF, dwarf_pc, pc_reg); | 
| Caroline Tice | b6f8d7e | 2011-02-15 18:10:01 +0000 | [diff] [blame] | 4379 | context.SetRegisterPlusOffset (pc_reg, 8); | 
| Caroline Tice | 8d681f5 | 2011-03-17 23:50:16 +0000 | [diff] [blame] | 4380 | const uint32_t pc = ReadCoreReg (PC_REG, &success); | 
| Caroline Tice | b6f8d7e | 2011-02-15 18:10:01 +0000 | [diff] [blame] | 4381 | if (!success) | 
|  | 4382 | return false; | 
|  | 4383 |  | 
| Caroline Tice | 8d681f5 | 2011-03-17 23:50:16 +0000 | [diff] [blame] | 4384 | if (!MemAWrite (context, address + offset, pc, addr_byte_size)) | 
| Caroline Tice | b6f8d7e | 2011-02-15 18:10:01 +0000 | [diff] [blame] | 4385 | return false; | 
|  | 4386 | } | 
|  | 4387 |  | 
|  | 4388 | // if wback then R[n] = R[n] - 4*BitCount(registers); | 
|  | 4389 | if (wback) | 
|  | 4390 | { | 
| Caroline Tice | af55656 | 2011-02-15 18:42:15 +0000 | [diff] [blame] | 4391 | offset = (addr_byte_size * BitCount (registers)) * -1; | 
|  | 4392 | context.type = EmulateInstruction::eContextAdjustBaseRegister; | 
|  | 4393 | context.SetImmediateSigned (offset); | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4394 | addr_t data = Rn + offset; | 
| Caroline Tice | af55656 | 2011-02-15 18:42:15 +0000 | [diff] [blame] | 4395 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, data)) | 
|  | 4396 | return false; | 
|  | 4397 | } | 
|  | 4398 | } | 
|  | 4399 | return true; | 
|  | 4400 | } | 
|  | 4401 |  | 
|  | 4402 | // STMIB (Store Multiple Increment Before) stores multiple registers to consecutive memory locations using an address | 
|  | 4403 | // from a base register.  The consecutive memory locations start just above this address, and the address of the last | 
|  | 4404 | // of those locations can optionally be written back to the base register. | 
|  | 4405 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 4406 | EmulateInstructionARM::EmulateSTMIB (const uint32_t opcode, const ARMEncoding encoding) | 
| Caroline Tice | af55656 | 2011-02-15 18:42:15 +0000 | [diff] [blame] | 4407 | { | 
|  | 4408 | #if 0 | 
|  | 4409 | if ConditionPassed() then | 
|  | 4410 | EncodingSpecificOperations(); | 
|  | 4411 | address = R[n] + 4; | 
|  | 4412 |  | 
|  | 4413 | for i = 0 to 14 | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4414 | if registers<i> == '1' then | 
| Caroline Tice | af55656 | 2011-02-15 18:42:15 +0000 | [diff] [blame] | 4415 | if i == n && wback && i != LowestSetBit(registers) then | 
|  | 4416 | MemA[address,4] = bits(32) UNKNOWN; | 
|  | 4417 | else | 
|  | 4418 | MemA[address,4] = R[i]; | 
|  | 4419 | address = address + 4; | 
|  | 4420 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4421 | if registers<15> == '1' then | 
| Caroline Tice | af55656 | 2011-02-15 18:42:15 +0000 | [diff] [blame] | 4422 | MemA[address,4] = PCStoreValue(); | 
|  | 4423 |  | 
|  | 4424 | if wback then R[n] = R[n] + 4*BitCount(registers); | 
|  | 4425 | #endif | 
|  | 4426 |  | 
|  | 4427 | bool success = false; | 
| Caroline Tice | af55656 | 2011-02-15 18:42:15 +0000 | [diff] [blame] | 4428 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 4429 | if (ConditionPassed(opcode)) | 
| Caroline Tice | af55656 | 2011-02-15 18:42:15 +0000 | [diff] [blame] | 4430 | { | 
|  | 4431 | uint32_t n; | 
|  | 4432 | uint32_t registers = 0; | 
|  | 4433 | bool wback; | 
|  | 4434 | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  | 4435 |  | 
|  | 4436 | // EncodingSpecificOperations(); | 
|  | 4437 | switch (encoding) | 
|  | 4438 | { | 
|  | 4439 | case eEncodingA1: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4440 | // n = UInt(Rn); registers = register_list; wback = (W == '1'); | 
| Caroline Tice | af55656 | 2011-02-15 18:42:15 +0000 | [diff] [blame] | 4441 | n = Bits32 (opcode, 19, 16); | 
|  | 4442 | registers = Bits32 (opcode, 15, 0); | 
|  | 4443 | wback = BitIsSet (opcode, 21); | 
|  | 4444 |  | 
|  | 4445 | // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; | 
|  | 4446 | if ((n == 15) && (BitCount (registers) < 1)) | 
|  | 4447 | return false; | 
|  | 4448 | break; | 
|  | 4449 | default: | 
|  | 4450 | return false; | 
|  | 4451 | } | 
|  | 4452 | // address = R[n] + 4; | 
|  | 4453 |  | 
|  | 4454 | int32_t offset = 0; | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4455 | addr_t Rn = ReadCoreReg (n, &success); | 
| Caroline Tice | af55656 | 2011-02-15 18:42:15 +0000 | [diff] [blame] | 4456 | if (!success) | 
|  | 4457 | return false; | 
|  | 4458 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4459 | addr_t address = Rn + addr_byte_size; | 
| Caroline Tice | af55656 | 2011-02-15 18:42:15 +0000 | [diff] [blame] | 4460 |  | 
|  | 4461 | EmulateInstruction::Context context; | 
|  | 4462 | context.type = EmulateInstruction::eContextRegisterStore; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 4463 | RegisterInfo base_reg; | 
|  | 4464 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
| Caroline Tice | af55656 | 2011-02-15 18:42:15 +0000 | [diff] [blame] | 4465 |  | 
|  | 4466 | uint32_t lowest_set_bit = 14; | 
|  | 4467 | // for i = 0 to 14 | 
|  | 4468 | for (int i = 0; i < 14; ++i) | 
|  | 4469 | { | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4470 | // if registers<i> == '1' then | 
| Caroline Tice | af55656 | 2011-02-15 18:42:15 +0000 | [diff] [blame] | 4471 | if (BitIsSet (registers, i)) | 
|  | 4472 | { | 
|  | 4473 | if (i < lowest_set_bit) | 
|  | 4474 | lowest_set_bit = i; | 
|  | 4475 | // if i == n && wback && i != LowestSetBit(registers) then | 
|  | 4476 | if ((i == n) && wback && (i != lowest_set_bit)) | 
|  | 4477 | // MemA[address,4] = bits(32) UNKNOWN; | 
|  | 4478 | WriteBits32UnknownToMemory (address + offset); | 
|  | 4479 | // else | 
|  | 4480 | else | 
|  | 4481 | { | 
|  | 4482 | // MemA[address,4] = R[i]; | 
|  | 4483 | uint32_t data = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + i, 0, &success); | 
|  | 4484 | if (!success) | 
|  | 4485 | return false; | 
|  | 4486 |  | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 4487 | RegisterInfo data_reg; | 
|  | 4488 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + i, data_reg); | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4489 | context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, offset + addr_byte_size); | 
| Caroline Tice | cc96eb5 | 2011-02-17 19:20:40 +0000 | [diff] [blame] | 4490 | if (!MemAWrite (context, address + offset, data, addr_byte_size)) | 
| Caroline Tice | af55656 | 2011-02-15 18:42:15 +0000 | [diff] [blame] | 4491 | return false; | 
|  | 4492 | } | 
|  | 4493 |  | 
|  | 4494 | // address = address + 4; | 
|  | 4495 | offset += addr_byte_size; | 
|  | 4496 | } | 
|  | 4497 | } | 
|  | 4498 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4499 | // if registers<15> == '1' then | 
| Caroline Tice | af55656 | 2011-02-15 18:42:15 +0000 | [diff] [blame] | 4500 | // MemA[address,4] = PCStoreValue(); | 
|  | 4501 | if (BitIsSet (registers, 15)) | 
|  | 4502 | { | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 4503 | RegisterInfo pc_reg; | 
|  | 4504 | GetRegisterInfo (eRegisterKindDWARF, dwarf_pc, pc_reg); | 
| Caroline Tice | af55656 | 2011-02-15 18:42:15 +0000 | [diff] [blame] | 4505 | context.SetRegisterPlusOffset (pc_reg, 8); | 
| Caroline Tice | 8d681f5 | 2011-03-17 23:50:16 +0000 | [diff] [blame] | 4506 | const uint32_t pc = ReadCoreReg (PC_REG, &success); | 
| Caroline Tice | af55656 | 2011-02-15 18:42:15 +0000 | [diff] [blame] | 4507 | if (!success) | 
|  | 4508 | return false; | 
|  | 4509 |  | 
| Caroline Tice | 8d681f5 | 2011-03-17 23:50:16 +0000 | [diff] [blame] | 4510 | if (!MemAWrite (context, address + offset, pc, addr_byte_size)) | 
| Caroline Tice | af55656 | 2011-02-15 18:42:15 +0000 | [diff] [blame] | 4511 | return false; | 
|  | 4512 | } | 
|  | 4513 |  | 
|  | 4514 | // if wback then R[n] = R[n] + 4*BitCount(registers); | 
|  | 4515 | if (wback) | 
|  | 4516 | { | 
| Caroline Tice | b6f8d7e | 2011-02-15 18:10:01 +0000 | [diff] [blame] | 4517 | offset = addr_byte_size * BitCount (registers); | 
|  | 4518 | context.type = EmulateInstruction::eContextAdjustBaseRegister; | 
|  | 4519 | context.SetImmediateSigned (offset); | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4520 | addr_t data = Rn + offset; | 
| Caroline Tice | b6f8d7e | 2011-02-15 18:10:01 +0000 | [diff] [blame] | 4521 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, data)) | 
|  | 4522 | return false; | 
|  | 4523 | } | 
|  | 4524 | } | 
|  | 4525 | return true; | 
|  | 4526 | } | 
| Caroline Tice | 7fac857 | 2011-02-15 22:53:54 +0000 | [diff] [blame] | 4527 |  | 
|  | 4528 | // STR (store immediate) calcualtes an address from a base register value and an immediate offset, and stores a word | 
|  | 4529 | // from a register to memory.  It can use offset, post-indexed, or pre-indexed addressing. | 
|  | 4530 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 4531 | EmulateInstructionARM::EmulateSTRThumb (const uint32_t opcode, const ARMEncoding encoding) | 
| Caroline Tice | 7fac857 | 2011-02-15 22:53:54 +0000 | [diff] [blame] | 4532 | { | 
|  | 4533 | #if 0 | 
|  | 4534 | if ConditionPassed() then | 
|  | 4535 | EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | 4536 | offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | 4537 | address = if index then offset_addr else R[n]; | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4538 | if UnalignedSupport() || address<1:0> == '00' then | 
| Caroline Tice | 7fac857 | 2011-02-15 22:53:54 +0000 | [diff] [blame] | 4539 | MemU[address,4] = R[t]; | 
|  | 4540 | else // Can only occur before ARMv7 | 
|  | 4541 | MemU[address,4] = bits(32) UNKNOWN; | 
|  | 4542 | if wback then R[n] = offset_addr; | 
|  | 4543 | #endif | 
| Caroline Tice | b6f8d7e | 2011-02-15 18:10:01 +0000 | [diff] [blame] | 4544 |  | 
| Caroline Tice | 7fac857 | 2011-02-15 22:53:54 +0000 | [diff] [blame] | 4545 | bool success = false; | 
| Caroline Tice | 7fac857 | 2011-02-15 22:53:54 +0000 | [diff] [blame] | 4546 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 4547 | if (ConditionPassed(opcode)) | 
| Caroline Tice | 7fac857 | 2011-02-15 22:53:54 +0000 | [diff] [blame] | 4548 | { | 
|  | 4549 | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  | 4550 |  | 
|  | 4551 | uint32_t t; | 
|  | 4552 | uint32_t n; | 
|  | 4553 | uint32_t imm32; | 
|  | 4554 | bool index; | 
|  | 4555 | bool add; | 
|  | 4556 | bool wback; | 
|  | 4557 | // EncodingSpecificOperations (); NullCheckIfThumbEE(n); | 
|  | 4558 | switch (encoding) | 
|  | 4559 | { | 
|  | 4560 | case eEncodingT1: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4561 | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm5:'00', 32); | 
| Caroline Tice | 7fac857 | 2011-02-15 22:53:54 +0000 | [diff] [blame] | 4562 | t = Bits32 (opcode, 2, 0); | 
|  | 4563 | n = Bits32 (opcode, 5, 3); | 
|  | 4564 | imm32 = Bits32 (opcode, 10, 6) << 2; | 
|  | 4565 |  | 
|  | 4566 | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | 4567 | index = true; | 
|  | 4568 | add = false; | 
|  | 4569 | wback = false; | 
|  | 4570 | break; | 
|  | 4571 |  | 
|  | 4572 | case eEncodingT2: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4573 | // t = UInt(Rt); n = 13; imm32 = ZeroExtend(imm8:'00', 32); | 
| Caroline Tice | 7fac857 | 2011-02-15 22:53:54 +0000 | [diff] [blame] | 4574 | t = Bits32 (opcode, 10, 8); | 
|  | 4575 | n = 13; | 
|  | 4576 | imm32 = Bits32 (opcode, 7, 0) << 2; | 
|  | 4577 |  | 
|  | 4578 | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | 4579 | index = true; | 
|  | 4580 | add = true; | 
|  | 4581 | wback = false; | 
|  | 4582 | break; | 
|  | 4583 |  | 
|  | 4584 | case eEncodingT3: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4585 | // if Rn == '1111' then UNDEFINED; | 
| Caroline Tice | 7fac857 | 2011-02-15 22:53:54 +0000 | [diff] [blame] | 4586 | if (Bits32 (opcode, 19, 16) == 15) | 
|  | 4587 | return false; | 
|  | 4588 |  | 
|  | 4589 | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32); | 
|  | 4590 | t = Bits32 (opcode, 15, 12); | 
|  | 4591 | n = Bits32 (opcode, 19, 16); | 
|  | 4592 | imm32 = Bits32 (opcode, 11, 0); | 
|  | 4593 |  | 
|  | 4594 | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | 4595 | index = true; | 
|  | 4596 | add = true; | 
|  | 4597 | wback = false; | 
|  | 4598 |  | 
|  | 4599 | // if t == 15 then UNPREDICTABLE; | 
|  | 4600 | if (t == 15) | 
|  | 4601 | return false; | 
|  | 4602 | break; | 
|  | 4603 |  | 
|  | 4604 | case eEncodingT4: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4605 | // if P == '1' && U == '1' && W == '0' then SEE STRT; | 
|  | 4606 | // if Rn == '1101' && P == '1' && U == '0' && W == '1' && imm8 == '00000100' then SEE PUSH; | 
|  | 4607 | // if Rn == '1111' || (P == '0' && W == '0') then UNDEFINED; | 
| Caroline Tice | 7fac857 | 2011-02-15 22:53:54 +0000 | [diff] [blame] | 4608 | if ((Bits32 (opcode, 19, 16) == 15) | 
|  | 4609 | || (BitIsClear (opcode, 10) && BitIsClear (opcode, 8))) | 
|  | 4610 | return false; | 
|  | 4611 |  | 
|  | 4612 | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32); | 
|  | 4613 | t = Bits32 (opcode, 15, 12); | 
|  | 4614 | n = Bits32 (opcode, 19, 16); | 
|  | 4615 | imm32 = Bits32 (opcode, 7, 0); | 
|  | 4616 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4617 | // index = (P == '1'); add = (U == '1'); wback = (W == '1'); | 
| Caroline Tice | 7fac857 | 2011-02-15 22:53:54 +0000 | [diff] [blame] | 4618 | index = BitIsSet (opcode, 10); | 
|  | 4619 | add = BitIsSet (opcode, 9); | 
|  | 4620 | wback = BitIsSet (opcode, 8); | 
|  | 4621 |  | 
|  | 4622 | // if t == 15 || (wback && n == t) then UNPREDICTABLE; | 
|  | 4623 | if ((t == 15) || (wback && (n == t))) | 
|  | 4624 | return false; | 
|  | 4625 | break; | 
|  | 4626 |  | 
|  | 4627 | default: | 
|  | 4628 | return false; | 
|  | 4629 | } | 
|  | 4630 |  | 
|  | 4631 | addr_t offset_addr; | 
|  | 4632 | addr_t address; | 
|  | 4633 |  | 
|  | 4634 | // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
| Caroline Tice | baf1f64 | 2011-03-24 19:23:45 +0000 | [diff] [blame] | 4635 | uint32_t base_address = ReadCoreReg (n, &success); | 
| Caroline Tice | 7fac857 | 2011-02-15 22:53:54 +0000 | [diff] [blame] | 4636 | if (!success) | 
|  | 4637 | return false; | 
|  | 4638 |  | 
|  | 4639 | if (add) | 
|  | 4640 | offset_addr = base_address + imm32; | 
|  | 4641 | else | 
|  | 4642 | offset_addr = base_address - imm32; | 
|  | 4643 |  | 
|  | 4644 | // address = if index then offset_addr else R[n]; | 
|  | 4645 | if (index) | 
|  | 4646 | address = offset_addr; | 
|  | 4647 | else | 
|  | 4648 | address = base_address; | 
|  | 4649 |  | 
|  | 4650 | EmulateInstruction::Context context; | 
|  | 4651 | context.type = eContextRegisterStore; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 4652 | RegisterInfo base_reg; | 
|  | 4653 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
| Caroline Tice | 7fac857 | 2011-02-15 22:53:54 +0000 | [diff] [blame] | 4654 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4655 | // if UnalignedSupport() || address<1:0> == '00' then | 
| Caroline Tice | 7fac857 | 2011-02-15 22:53:54 +0000 | [diff] [blame] | 4656 | if (UnalignedSupport () || (BitIsClear (address, 1) && BitIsClear (address, 0))) | 
|  | 4657 | { | 
|  | 4658 | // MemU[address,4] = R[t]; | 
|  | 4659 | uint32_t data = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + t, 0, &success); | 
|  | 4660 | if (!success) | 
|  | 4661 | return false; | 
|  | 4662 |  | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 4663 | RegisterInfo data_reg; | 
|  | 4664 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + t, data_reg); | 
| Caroline Tice | 7fac857 | 2011-02-15 22:53:54 +0000 | [diff] [blame] | 4665 | int32_t offset = address - base_address; | 
|  | 4666 | context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, offset); | 
| Caroline Tice | cc96eb5 | 2011-02-17 19:20:40 +0000 | [diff] [blame] | 4667 | if (!MemUWrite (context, address, data, addr_byte_size)) | 
| Caroline Tice | 7fac857 | 2011-02-15 22:53:54 +0000 | [diff] [blame] | 4668 | return false; | 
|  | 4669 | } | 
|  | 4670 | else | 
|  | 4671 | { | 
|  | 4672 | // MemU[address,4] = bits(32) UNKNOWN; | 
|  | 4673 | WriteBits32UnknownToMemory (address); | 
|  | 4674 | } | 
|  | 4675 |  | 
|  | 4676 | // if wback then R[n] = offset_addr; | 
|  | 4677 | if (wback) | 
|  | 4678 | { | 
|  | 4679 | context.type = eContextRegisterLoad; | 
|  | 4680 | context.SetAddress (offset_addr); | 
|  | 4681 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr)) | 
|  | 4682 | return false; | 
|  | 4683 | } | 
|  | 4684 | } | 
|  | 4685 | return true; | 
|  | 4686 | } | 
| Caroline Tice | af55656 | 2011-02-15 18:42:15 +0000 | [diff] [blame] | 4687 |  | 
| Caroline Tice | 3fd63e9 | 2011-02-16 00:33:43 +0000 | [diff] [blame] | 4688 | // STR (Store Register) calculates an address from a base register value and an offset register value, stores a | 
|  | 4689 | // word from a register to memory.   The offset register value can optionally be shifted. | 
|  | 4690 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 4691 | EmulateInstructionARM::EmulateSTRRegister (const uint32_t opcode, const ARMEncoding encoding) | 
| Caroline Tice | 3fd63e9 | 2011-02-16 00:33:43 +0000 | [diff] [blame] | 4692 | { | 
|  | 4693 | #if 0 | 
|  | 4694 | if ConditionPassed() then | 
|  | 4695 | EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | 4696 | offset = Shift(R[m], shift_t, shift_n, APSR.C); | 
|  | 4697 | offset_addr = if add then (R[n] + offset) else (R[n] - offset); | 
|  | 4698 | address = if index then offset_addr else R[n]; | 
|  | 4699 | if t == 15 then // Only possible for encoding A1 | 
|  | 4700 | data = PCStoreValue(); | 
|  | 4701 | else | 
|  | 4702 | data = R[t]; | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4703 | if UnalignedSupport() || address<1:0> == '00' || CurrentInstrSet() == InstrSet_ARM then | 
| Caroline Tice | 3fd63e9 | 2011-02-16 00:33:43 +0000 | [diff] [blame] | 4704 | MemU[address,4] = data; | 
|  | 4705 | else // Can only occur before ARMv7 | 
|  | 4706 | MemU[address,4] = bits(32) UNKNOWN; | 
|  | 4707 | if wback then R[n] = offset_addr; | 
|  | 4708 | #endif | 
|  | 4709 |  | 
|  | 4710 | bool success = false; | 
| Caroline Tice | 3fd63e9 | 2011-02-16 00:33:43 +0000 | [diff] [blame] | 4711 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 4712 | if (ConditionPassed(opcode)) | 
| Caroline Tice | 3fd63e9 | 2011-02-16 00:33:43 +0000 | [diff] [blame] | 4713 | { | 
|  | 4714 | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  | 4715 |  | 
|  | 4716 | uint32_t t; | 
|  | 4717 | uint32_t n; | 
|  | 4718 | uint32_t m; | 
|  | 4719 | ARM_ShifterType shift_t; | 
|  | 4720 | uint32_t shift_n; | 
|  | 4721 | bool index; | 
|  | 4722 | bool add; | 
|  | 4723 | bool wback; | 
|  | 4724 |  | 
|  | 4725 | // EncodingSpecificOperations (); NullCheckIfThumbEE(n); | 
|  | 4726 | switch (encoding) | 
|  | 4727 | { | 
|  | 4728 | case eEncodingT1: | 
|  | 4729 | // if CurrentInstrSet() == InstrSet_ThumbEE then SEE "Modified operation in ThumbEE"; | 
|  | 4730 | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); | 
|  | 4731 | t = Bits32 (opcode, 2, 0); | 
|  | 4732 | n = Bits32 (opcode, 5, 3); | 
|  | 4733 | m = Bits32 (opcode, 8, 6); | 
|  | 4734 |  | 
|  | 4735 | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | 4736 | index = true; | 
|  | 4737 | add = true; | 
|  | 4738 | wback = false; | 
|  | 4739 |  | 
|  | 4740 | // (shift_t, shift_n) = (SRType_LSL, 0); | 
|  | 4741 | shift_t = SRType_LSL; | 
|  | 4742 | shift_n = 0; | 
|  | 4743 | break; | 
|  | 4744 |  | 
|  | 4745 | case eEncodingT2: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4746 | // if Rn == '1111' then UNDEFINED; | 
| Caroline Tice | 3fd63e9 | 2011-02-16 00:33:43 +0000 | [diff] [blame] | 4747 | if (Bits32 (opcode, 19, 16) == 15) | 
|  | 4748 | return false; | 
|  | 4749 |  | 
|  | 4750 | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); | 
|  | 4751 | t = Bits32 (opcode, 15, 12); | 
|  | 4752 | n = Bits32 (opcode, 19, 16); | 
|  | 4753 | m = Bits32 (opcode, 3, 0); | 
|  | 4754 |  | 
|  | 4755 | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | 4756 | index = true; | 
|  | 4757 | add = true; | 
|  | 4758 | wback = false; | 
|  | 4759 |  | 
|  | 4760 | // (shift_t, shift_n) = (SRType_LSL, UInt(imm2)); | 
|  | 4761 | shift_t = SRType_LSL; | 
|  | 4762 | shift_n = Bits32 (opcode, 5, 4); | 
|  | 4763 |  | 
|  | 4764 | // if t == 15 || BadReg(m) then UNPREDICTABLE; | 
|  | 4765 | if ((t == 15) || (BadReg (m))) | 
|  | 4766 | return false; | 
|  | 4767 | break; | 
|  | 4768 |  | 
|  | 4769 | case eEncodingA1: | 
|  | 4770 | { | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4771 | // if P == '0' && W == '1' then SEE STRT; | 
| Caroline Tice | 3fd63e9 | 2011-02-16 00:33:43 +0000 | [diff] [blame] | 4772 | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); | 
|  | 4773 | t = Bits32 (opcode, 15, 12); | 
|  | 4774 | n = Bits32 (opcode, 19, 16); | 
|  | 4775 | m = Bits32 (opcode, 3, 0); | 
|  | 4776 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4777 | // index = (P == '1');	add = (U == '1');	wback = (P == '0') || (W == '1'); | 
| Caroline Tice | 3fd63e9 | 2011-02-16 00:33:43 +0000 | [diff] [blame] | 4778 | index = BitIsSet (opcode, 24); | 
|  | 4779 | add = BitIsSet (opcode, 23); | 
|  | 4780 | wback = (BitIsClear (opcode, 24) || BitIsSet (opcode, 21)); | 
|  | 4781 |  | 
|  | 4782 | // (shift_t, shift_n) = DecodeImmShift(type, imm5); | 
|  | 4783 | uint32_t typ = Bits32 (opcode, 6, 5); | 
|  | 4784 | uint32_t imm5 = Bits32 (opcode, 11, 7); | 
|  | 4785 | shift_n = DecodeImmShift(typ, imm5, shift_t); | 
|  | 4786 |  | 
|  | 4787 | // if m == 15 then UNPREDICTABLE; | 
|  | 4788 | if (m == 15) | 
|  | 4789 | return false; | 
|  | 4790 |  | 
|  | 4791 | // if wback && (n == 15 || n == t) then UNPREDICTABLE; | 
|  | 4792 | if (wback && ((n == 15) || (n == t))) | 
|  | 4793 | return false; | 
|  | 4794 |  | 
|  | 4795 | break; | 
|  | 4796 | } | 
|  | 4797 | default: | 
|  | 4798 | return false; | 
|  | 4799 | } | 
|  | 4800 |  | 
|  | 4801 | addr_t offset_addr; | 
|  | 4802 | addr_t address; | 
|  | 4803 | int32_t offset = 0; | 
|  | 4804 |  | 
|  | 4805 | addr_t base_address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success); | 
|  | 4806 | if (!success) | 
|  | 4807 | return false; | 
|  | 4808 |  | 
|  | 4809 | uint32_t Rm_data = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + m, 0, &success); | 
|  | 4810 | if (!success) | 
|  | 4811 | return false; | 
|  | 4812 |  | 
|  | 4813 | // offset = Shift(R[m], shift_t, shift_n, APSR.C); | 
| Johnny Chen | a4438a7 | 2011-06-02 22:50:51 +0000 | [diff] [blame] | 4814 | offset = Shift (Rm_data, shift_t, shift_n, APSR_C, &success); | 
|  | 4815 | if (!success) | 
|  | 4816 | return false; | 
| Caroline Tice | 3fd63e9 | 2011-02-16 00:33:43 +0000 | [diff] [blame] | 4817 |  | 
|  | 4818 | // offset_addr = if add then (R[n] + offset) else (R[n] - offset); | 
|  | 4819 | if (add) | 
|  | 4820 | offset_addr = base_address + offset; | 
|  | 4821 | else | 
|  | 4822 | offset_addr = base_address - offset; | 
|  | 4823 |  | 
|  | 4824 | // address = if index then offset_addr else R[n]; | 
|  | 4825 | if (index) | 
|  | 4826 | address = offset_addr; | 
|  | 4827 | else | 
|  | 4828 | address = base_address; | 
|  | 4829 |  | 
|  | 4830 | uint32_t data; | 
|  | 4831 | // if t == 15 then // Only possible for encoding A1 | 
|  | 4832 | if (t == 15) | 
|  | 4833 | // data = PCStoreValue(); | 
| Caroline Tice | 8d681f5 | 2011-03-17 23:50:16 +0000 | [diff] [blame] | 4834 | data = ReadCoreReg (PC_REG, &success); | 
| Caroline Tice | 3fd63e9 | 2011-02-16 00:33:43 +0000 | [diff] [blame] | 4835 | else | 
|  | 4836 | // data = R[t]; | 
|  | 4837 | data = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + t, 0, &success); | 
|  | 4838 |  | 
|  | 4839 | if (!success) | 
|  | 4840 | return false; | 
|  | 4841 |  | 
|  | 4842 | EmulateInstruction::Context context; | 
|  | 4843 | context.type = eContextRegisterStore; | 
|  | 4844 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4845 | // if UnalignedSupport() || address<1:0> == '00' || CurrentInstrSet() == InstrSet_ARM then | 
| Caroline Tice | 3fd63e9 | 2011-02-16 00:33:43 +0000 | [diff] [blame] | 4846 | if (UnalignedSupport () | 
|  | 4847 | || (BitIsClear (address, 1) && BitIsClear (address, 0)) | 
|  | 4848 | || CurrentInstrSet() == eModeARM) | 
|  | 4849 | { | 
|  | 4850 | // MemU[address,4] = data; | 
|  | 4851 |  | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 4852 | RegisterInfo base_reg; | 
|  | 4853 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 +  n, base_reg); | 
| Caroline Tice | 3fd63e9 | 2011-02-16 00:33:43 +0000 | [diff] [blame] | 4854 |  | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 4855 | RegisterInfo data_reg; | 
|  | 4856 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + t, data_reg); | 
| Caroline Tice | 3fd63e9 | 2011-02-16 00:33:43 +0000 | [diff] [blame] | 4857 |  | 
|  | 4858 | context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, address - base_address); | 
| Caroline Tice | cc96eb5 | 2011-02-17 19:20:40 +0000 | [diff] [blame] | 4859 | if (!MemUWrite (context, address, data, addr_byte_size)) | 
| Caroline Tice | 3fd63e9 | 2011-02-16 00:33:43 +0000 | [diff] [blame] | 4860 | return false; | 
|  | 4861 |  | 
|  | 4862 | } | 
|  | 4863 | else | 
|  | 4864 | // MemU[address,4] = bits(32) UNKNOWN; | 
|  | 4865 | WriteBits32UnknownToMemory (address); | 
|  | 4866 |  | 
|  | 4867 | // if wback then R[n] = offset_addr; | 
|  | 4868 | if (wback) | 
|  | 4869 | { | 
|  | 4870 | context.type = eContextRegisterLoad; | 
|  | 4871 | context.SetAddress (offset_addr); | 
|  | 4872 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr)) | 
|  | 4873 | return false; | 
|  | 4874 | } | 
|  | 4875 |  | 
|  | 4876 | } | 
|  | 4877 | return true; | 
|  | 4878 | } | 
| Caroline Tice | 73a29de | 2011-02-16 20:22:22 +0000 | [diff] [blame] | 4879 |  | 
|  | 4880 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 4881 | EmulateInstructionARM::EmulateSTRBThumb (const uint32_t opcode, const ARMEncoding encoding) | 
| Caroline Tice | 73a29de | 2011-02-16 20:22:22 +0000 | [diff] [blame] | 4882 | { | 
|  | 4883 | #if 0 | 
|  | 4884 | if ConditionPassed() then | 
|  | 4885 | EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | 4886 | offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | 4887 | address = if index then offset_addr else R[n]; | 
|  | 4888 | MemU[address,1] = R[t]<7:0>; | 
|  | 4889 | if wback then R[n] = offset_addr; | 
|  | 4890 | #endif | 
|  | 4891 |  | 
|  | 4892 |  | 
|  | 4893 | bool success = false; | 
| Caroline Tice | 73a29de | 2011-02-16 20:22:22 +0000 | [diff] [blame] | 4894 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 4895 | if (ConditionPassed(opcode)) | 
| Caroline Tice | 73a29de | 2011-02-16 20:22:22 +0000 | [diff] [blame] | 4896 | { | 
|  | 4897 | uint32_t t; | 
|  | 4898 | uint32_t n; | 
|  | 4899 | uint32_t imm32; | 
|  | 4900 | bool index; | 
|  | 4901 | bool add; | 
|  | 4902 | bool wback; | 
|  | 4903 | // EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | 4904 | switch (encoding) | 
|  | 4905 | { | 
|  | 4906 | case eEncodingT1: | 
|  | 4907 | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm5, 32); | 
|  | 4908 | t = Bits32 (opcode, 2, 0); | 
|  | 4909 | n = Bits32 (opcode, 5, 3); | 
|  | 4910 | imm32 = Bits32 (opcode, 10, 6); | 
|  | 4911 |  | 
|  | 4912 | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | 4913 | index = true; | 
|  | 4914 | add = true; | 
|  | 4915 | wback = false; | 
|  | 4916 | break; | 
|  | 4917 |  | 
|  | 4918 | case eEncodingT2: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4919 | // if Rn == '1111' then UNDEFINED; | 
| Caroline Tice | 73a29de | 2011-02-16 20:22:22 +0000 | [diff] [blame] | 4920 | if (Bits32 (opcode, 19, 16) == 15) | 
|  | 4921 | return false; | 
|  | 4922 |  | 
|  | 4923 | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32); | 
|  | 4924 | t = Bits32 (opcode, 15, 12); | 
|  | 4925 | n = Bits32 (opcode, 19, 16); | 
|  | 4926 | imm32 = Bits32 (opcode, 11, 0); | 
|  | 4927 |  | 
|  | 4928 | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | 4929 | index = true; | 
|  | 4930 | add = true; | 
|  | 4931 | wback = false; | 
|  | 4932 |  | 
|  | 4933 | // if BadReg(t) then UNPREDICTABLE; | 
|  | 4934 | if (BadReg (t)) | 
|  | 4935 | return false; | 
|  | 4936 | break; | 
|  | 4937 |  | 
|  | 4938 | case eEncodingT3: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4939 | // if P == '1' && U == '1' && W == '0' then SEE STRBT; | 
|  | 4940 | // if Rn == '1111' || (P == '0' && W == '0') then UNDEFINED; | 
| Caroline Tice | 73a29de | 2011-02-16 20:22:22 +0000 | [diff] [blame] | 4941 | if (Bits32 (opcode, 19, 16) == 15) | 
|  | 4942 | return false; | 
|  | 4943 |  | 
|  | 4944 | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32); | 
|  | 4945 | t = Bits32 (opcode, 15, 12); | 
|  | 4946 | n = Bits32 (opcode, 19, 16); | 
|  | 4947 | imm32 = Bits32 (opcode, 7, 0); | 
|  | 4948 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 4949 | // index = (P == '1'); add = (U == '1'); wback = (W == '1'); | 
| Caroline Tice | 73a29de | 2011-02-16 20:22:22 +0000 | [diff] [blame] | 4950 | index = BitIsSet (opcode, 10); | 
|  | 4951 | add = BitIsSet (opcode, 9); | 
|  | 4952 | wback = BitIsSet (opcode, 8); | 
|  | 4953 |  | 
|  | 4954 | // if BadReg(t) || (wback && n == t) then UNPREDICTABLE | 
|  | 4955 | if ((BadReg (t)) || (wback && (n == t))) | 
|  | 4956 | return false; | 
|  | 4957 | break; | 
|  | 4958 |  | 
|  | 4959 | default: | 
|  | 4960 | return false; | 
|  | 4961 | } | 
|  | 4962 |  | 
|  | 4963 | addr_t offset_addr; | 
|  | 4964 | addr_t address; | 
|  | 4965 | addr_t base_address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success); | 
|  | 4966 | if (!success) | 
|  | 4967 | return false; | 
|  | 4968 |  | 
|  | 4969 | // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | 4970 | if (add) | 
|  | 4971 | offset_addr = base_address + imm32; | 
|  | 4972 | else | 
|  | 4973 | offset_addr = base_address - imm32; | 
|  | 4974 |  | 
|  | 4975 | // address = if index then offset_addr else R[n]; | 
|  | 4976 | if (index) | 
|  | 4977 | address = offset_addr; | 
|  | 4978 | else | 
|  | 4979 | address = base_address; | 
|  | 4980 |  | 
| Caroline Tice | cc96eb5 | 2011-02-17 19:20:40 +0000 | [diff] [blame] | 4981 | // MemU[address,1] = R[t]<7:0> | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 4982 | RegisterInfo base_reg; | 
|  | 4983 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
| Caroline Tice | 73a29de | 2011-02-16 20:22:22 +0000 | [diff] [blame] | 4984 |  | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 4985 | RegisterInfo data_reg; | 
|  | 4986 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + t, data_reg); | 
| Caroline Tice | 73a29de | 2011-02-16 20:22:22 +0000 | [diff] [blame] | 4987 |  | 
|  | 4988 | EmulateInstruction::Context context; | 
|  | 4989 | context.type = eContextRegisterStore; | 
|  | 4990 | context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, address - base_address); | 
|  | 4991 |  | 
|  | 4992 | uint32_t data = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + t, 0, &success); | 
|  | 4993 | if (!success) | 
|  | 4994 | return false; | 
|  | 4995 |  | 
|  | 4996 | data = Bits32 (data, 7, 0); | 
|  | 4997 |  | 
| Caroline Tice | cc96eb5 | 2011-02-17 19:20:40 +0000 | [diff] [blame] | 4998 | if (!MemUWrite (context, address, data, 1)) | 
| Caroline Tice | 73a29de | 2011-02-16 20:22:22 +0000 | [diff] [blame] | 4999 | return false; | 
|  | 5000 |  | 
|  | 5001 | // if wback then R[n] = offset_addr; | 
|  | 5002 | if (wback) | 
|  | 5003 | { | 
|  | 5004 | context.type = eContextRegisterLoad; | 
|  | 5005 | context.SetAddress (offset_addr); | 
|  | 5006 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr)) | 
|  | 5007 | return false; | 
|  | 5008 | } | 
|  | 5009 |  | 
|  | 5010 | } | 
|  | 5011 |  | 
|  | 5012 | return true; | 
|  | 5013 | } | 
| Caroline Tice | 8ce836d | 2011-03-16 22:46:55 +0000 | [diff] [blame] | 5014 |  | 
|  | 5015 | // STRH (register) calculates an address from a base register value and an offset register value, and stores a | 
|  | 5016 | // halfword from a register to memory.  The offset register alue can be shifted left by 0, 1, 2, or 3 bits. | 
|  | 5017 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 5018 | EmulateInstructionARM::EmulateSTRHRegister (const uint32_t opcode, const ARMEncoding encoding) | 
| Caroline Tice | 8ce836d | 2011-03-16 22:46:55 +0000 | [diff] [blame] | 5019 | { | 
|  | 5020 | #if 0 | 
|  | 5021 | if ConditionPassed() then | 
|  | 5022 | EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | 5023 | offset = Shift(R[m], shift_t, shift_n, APSR.C); | 
|  | 5024 | offset_addr = if add then (R[n] + offset) else (R[n] - offset); | 
|  | 5025 | address = if index then offset_addr else R[n]; | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 5026 | if UnalignedSupport() || address<0> == '0' then | 
| Caroline Tice | 8ce836d | 2011-03-16 22:46:55 +0000 | [diff] [blame] | 5027 | MemU[address,2] = R[t]<15:0>; | 
|  | 5028 | else // Can only occur before ARMv7 | 
|  | 5029 | MemU[address,2] = bits(16) UNKNOWN; | 
|  | 5030 | if wback then R[n] = offset_addr; | 
|  | 5031 | #endif | 
|  | 5032 |  | 
|  | 5033 | bool success = false; | 
| Caroline Tice | 8ce836d | 2011-03-16 22:46:55 +0000 | [diff] [blame] | 5034 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 5035 | if (ConditionPassed(opcode)) | 
| Caroline Tice | 8ce836d | 2011-03-16 22:46:55 +0000 | [diff] [blame] | 5036 | { | 
|  | 5037 | uint32_t t; | 
|  | 5038 | uint32_t n; | 
|  | 5039 | uint32_t m; | 
|  | 5040 | bool index; | 
|  | 5041 | bool add; | 
|  | 5042 | bool wback; | 
|  | 5043 | ARM_ShifterType shift_t; | 
|  | 5044 | uint32_t shift_n; | 
|  | 5045 |  | 
|  | 5046 | // EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | 5047 | switch (encoding) | 
|  | 5048 | { | 
|  | 5049 | case eEncodingT1: | 
|  | 5050 | // if CurrentInstrSet() == InstrSet_ThumbEE then SEE "Modified operation in ThumbEE"; | 
|  | 5051 | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); | 
|  | 5052 | t = Bits32 (opcode, 2, 0); | 
|  | 5053 | n = Bits32 (opcode, 5, 3); | 
|  | 5054 | m = Bits32 (opcode, 8, 6); | 
|  | 5055 |  | 
|  | 5056 | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | 5057 | index = true; | 
|  | 5058 | add = true; | 
|  | 5059 | wback = false; | 
|  | 5060 |  | 
|  | 5061 | // (shift_t, shift_n) = (SRType_LSL, 0); | 
|  | 5062 | shift_t = SRType_LSL; | 
|  | 5063 | shift_n = 0; | 
|  | 5064 |  | 
|  | 5065 | break; | 
|  | 5066 |  | 
|  | 5067 | case eEncodingT2: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 5068 | // if Rn == '1111' then UNDEFINED; | 
| Caroline Tice | 8ce836d | 2011-03-16 22:46:55 +0000 | [diff] [blame] | 5069 | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); | 
|  | 5070 | t = Bits32 (opcode, 15, 12); | 
|  | 5071 | n = Bits32 (opcode, 19, 16); | 
|  | 5072 | m = Bits32 (opcode, 3, 0); | 
|  | 5073 | if (n == 15) | 
|  | 5074 | return false; | 
|  | 5075 |  | 
|  | 5076 | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | 5077 | index = true; | 
|  | 5078 | add = true; | 
|  | 5079 | wback = false; | 
|  | 5080 |  | 
|  | 5081 | // (shift_t, shift_n) = (SRType_LSL, UInt(imm2)); | 
|  | 5082 | shift_t = SRType_LSL; | 
|  | 5083 | shift_n = Bits32 (opcode, 5, 4); | 
|  | 5084 |  | 
|  | 5085 | // if BadReg(t) || BadReg(m) then UNPREDICTABLE; | 
|  | 5086 | if (BadReg (t) || BadReg (m)) | 
|  | 5087 | return false; | 
|  | 5088 |  | 
|  | 5089 | break; | 
|  | 5090 |  | 
|  | 5091 | case eEncodingA1: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 5092 | // if P == '0' && W == '1' then SEE STRHT; | 
| Caroline Tice | 8ce836d | 2011-03-16 22:46:55 +0000 | [diff] [blame] | 5093 | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); | 
|  | 5094 | t = Bits32 (opcode, 15, 12); | 
|  | 5095 | n = Bits32 (opcode, 19, 16); | 
|  | 5096 | m = Bits32 (opcode, 3, 0); | 
|  | 5097 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 5098 | // index = (P == '1');	add = (U == '1');	wback = (P == '0') || (W == '1'); | 
| Caroline Tice | 8ce836d | 2011-03-16 22:46:55 +0000 | [diff] [blame] | 5099 | index = BitIsSet (opcode, 24); | 
|  | 5100 | add = BitIsSet (opcode, 23); | 
|  | 5101 | wback = (BitIsClear (opcode, 24) || BitIsSet (opcode, 21)); | 
|  | 5102 |  | 
|  | 5103 | // (shift_t, shift_n) = (SRType_LSL, 0); | 
|  | 5104 | shift_t = SRType_LSL; | 
|  | 5105 | shift_n = 0; | 
|  | 5106 |  | 
|  | 5107 | // if t == 15 || m == 15 then UNPREDICTABLE; | 
|  | 5108 | if ((t == 15) || (m == 15)) | 
|  | 5109 | return false; | 
|  | 5110 |  | 
|  | 5111 | // if wback && (n == 15 || n == t) then UNPREDICTABLE; | 
|  | 5112 | if (wback && ((n == 15) || (n == t))) | 
|  | 5113 | return false; | 
|  | 5114 |  | 
|  | 5115 | break; | 
|  | 5116 |  | 
|  | 5117 | default: | 
|  | 5118 | return false; | 
|  | 5119 | } | 
|  | 5120 |  | 
|  | 5121 | uint32_t Rm = ReadCoreReg (m, &success); | 
|  | 5122 | if (!success) | 
|  | 5123 | return false; | 
|  | 5124 |  | 
|  | 5125 | uint32_t Rn = ReadCoreReg (n, &success); | 
|  | 5126 | if (!success) | 
|  | 5127 | return false; | 
|  | 5128 |  | 
|  | 5129 | // offset = Shift(R[m], shift_t, shift_n, APSR.C); | 
| Johnny Chen | a4438a7 | 2011-06-02 22:50:51 +0000 | [diff] [blame] | 5130 | uint32_t offset = Shift (Rm, shift_t, shift_n, APSR_C, &success); | 
|  | 5131 | if (!success) | 
|  | 5132 | return false; | 
| Caroline Tice | 8ce836d | 2011-03-16 22:46:55 +0000 | [diff] [blame] | 5133 |  | 
|  | 5134 | // offset_addr = if add then (R[n] + offset) else (R[n] - offset); | 
|  | 5135 | addr_t offset_addr; | 
|  | 5136 | if (add) | 
|  | 5137 | offset_addr = Rn + offset; | 
|  | 5138 | else | 
|  | 5139 | offset_addr = Rn - offset; | 
|  | 5140 |  | 
|  | 5141 | // address = if index then offset_addr else R[n]; | 
|  | 5142 | addr_t address; | 
|  | 5143 | if (index) | 
|  | 5144 | address = offset_addr; | 
|  | 5145 | else | 
|  | 5146 | address = Rn; | 
|  | 5147 |  | 
|  | 5148 | EmulateInstruction::Context context; | 
|  | 5149 | context.type = eContextRegisterStore; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 5150 | RegisterInfo base_reg; | 
|  | 5151 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
|  | 5152 | RegisterInfo offset_reg; | 
|  | 5153 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + m, offset_reg); | 
| Caroline Tice | 8ce836d | 2011-03-16 22:46:55 +0000 | [diff] [blame] | 5154 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 5155 | // if UnalignedSupport() || address<0> == '0' then | 
| Caroline Tice | 8ce836d | 2011-03-16 22:46:55 +0000 | [diff] [blame] | 5156 | if (UnalignedSupport() || BitIsClear (address, 0)) | 
|  | 5157 | { | 
|  | 5158 | // MemU[address,2] = R[t]<15:0>; | 
|  | 5159 | uint32_t Rt = ReadCoreReg (t, &success); | 
|  | 5160 | if (!success) | 
|  | 5161 | return false; | 
|  | 5162 |  | 
|  | 5163 | EmulateInstruction::Context context; | 
|  | 5164 | context.type = eContextRegisterStore; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 5165 | RegisterInfo base_reg; | 
|  | 5166 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
|  | 5167 | RegisterInfo offset_reg; | 
|  | 5168 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + m, offset_reg); | 
|  | 5169 | RegisterInfo data_reg; | 
|  | 5170 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + t, data_reg); | 
| Caroline Tice | 8ce836d | 2011-03-16 22:46:55 +0000 | [diff] [blame] | 5171 | context.SetRegisterToRegisterPlusIndirectOffset (base_reg, offset_reg, data_reg); | 
|  | 5172 |  | 
|  | 5173 | if (!MemUWrite (context, address, Bits32 (Rt, 15, 0), 2)) | 
|  | 5174 | return false; | 
|  | 5175 | } | 
|  | 5176 | else // Can only occur before ARMv7 | 
|  | 5177 | { | 
|  | 5178 | // MemU[address,2] = bits(16) UNKNOWN; | 
|  | 5179 | } | 
|  | 5180 |  | 
|  | 5181 | // if wback then R[n] = offset_addr; | 
|  | 5182 | if (wback) | 
|  | 5183 | { | 
|  | 5184 | context.type = eContextAdjustBaseRegister; | 
|  | 5185 | context.SetAddress (offset_addr); | 
|  | 5186 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr)) | 
|  | 5187 | return false; | 
|  | 5188 | } | 
|  | 5189 | } | 
|  | 5190 |  | 
|  | 5191 | return true; | 
|  | 5192 | } | 
| Caroline Tice | 3fd63e9 | 2011-02-16 00:33:43 +0000 | [diff] [blame] | 5193 |  | 
| Johnny Chen | 157b959 | 2011-02-18 21:13:05 +0000 | [diff] [blame] | 5194 | // Add with Carry (immediate) adds an immediate value and the carry flag value to a register value, | 
|  | 5195 | // and writes the result to the destination register.  It can optionally update the condition flags | 
|  | 5196 | // based on the result. | 
|  | 5197 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 5198 | EmulateInstructionARM::EmulateADCImm (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | 157b959 | 2011-02-18 21:13:05 +0000 | [diff] [blame] | 5199 | { | 
|  | 5200 | #if 0 | 
|  | 5201 | // ARM pseudo code... | 
|  | 5202 | if ConditionPassed() then | 
|  | 5203 | EncodingSpecificOperations(); | 
|  | 5204 | (result, carry, overflow) = AddWithCarry(R[n], imm32, APSR.C); | 
|  | 5205 | if d == 15 then         // Can only occur for ARM encoding | 
|  | 5206 | ALUWritePC(result); // setflags is always FALSE here | 
|  | 5207 | else | 
|  | 5208 | R[d] = result; | 
|  | 5209 | if setflags then | 
|  | 5210 | APSR.N = result<31>; | 
|  | 5211 | APSR.Z = IsZeroBit(result); | 
|  | 5212 | APSR.C = carry; | 
|  | 5213 | APSR.V = overflow; | 
|  | 5214 | #endif | 
|  | 5215 |  | 
|  | 5216 | bool success = false; | 
| Johnny Chen | 157b959 | 2011-02-18 21:13:05 +0000 | [diff] [blame] | 5217 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 5218 | if (ConditionPassed(opcode)) | 
| Johnny Chen | 157b959 | 2011-02-18 21:13:05 +0000 | [diff] [blame] | 5219 | { | 
|  | 5220 | uint32_t Rd, Rn; | 
|  | 5221 | uint32_t imm32; // the immediate value to be added to the value obtained from Rn | 
|  | 5222 | bool setflags; | 
|  | 5223 | switch (encoding) | 
|  | 5224 | { | 
|  | 5225 | case eEncodingT1: | 
|  | 5226 | Rd = Bits32(opcode, 11, 8); | 
|  | 5227 | Rn = Bits32(opcode, 19, 16); | 
|  | 5228 | setflags = BitIsSet(opcode, 20); | 
|  | 5229 | imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8) | 
|  | 5230 | if (BadReg(Rd) || BadReg(Rn)) | 
|  | 5231 | return false; | 
|  | 5232 | break; | 
|  | 5233 | case eEncodingA1: | 
|  | 5234 | Rd = Bits32(opcode, 15, 12); | 
|  | 5235 | Rn = Bits32(opcode, 19, 16); | 
|  | 5236 | setflags = BitIsSet(opcode, 20); | 
|  | 5237 | imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12) | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 5238 |  | 
| Johnny Chen | 157b959 | 2011-02-18 21:13:05 +0000 | [diff] [blame] | 5239 | if (Rd == 15 && setflags) | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 5240 | return EmulateSUBSPcLrEtc (opcode, encoding); | 
| Johnny Chen | 157b959 | 2011-02-18 21:13:05 +0000 | [diff] [blame] | 5241 | break; | 
|  | 5242 | default: | 
|  | 5243 | return false; | 
|  | 5244 | } | 
|  | 5245 |  | 
|  | 5246 | // Read the first operand. | 
|  | 5247 | int32_t val1 = ReadCoreReg(Rn, &success); | 
|  | 5248 | if (!success) | 
|  | 5249 | return false; | 
|  | 5250 |  | 
|  | 5251 | AddWithCarryResult res = AddWithCarry(val1, imm32, APSR_C); | 
|  | 5252 |  | 
|  | 5253 | EmulateInstruction::Context context; | 
|  | 5254 | context.type = EmulateInstruction::eContextImmediate; | 
|  | 5255 | context.SetNoArgs (); | 
|  | 5256 |  | 
|  | 5257 | if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, res.carry_out, res.overflow)) | 
|  | 5258 | return false; | 
|  | 5259 | } | 
|  | 5260 | return true; | 
|  | 5261 | } | 
|  | 5262 |  | 
|  | 5263 | // Add with Carry (register) adds a register value, the carry flag value, and an optionally-shifted | 
|  | 5264 | // register value, and writes the result to the destination register.  It can optionally update the | 
|  | 5265 | // condition flags based on the result. | 
|  | 5266 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 5267 | EmulateInstructionARM::EmulateADCReg (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | 157b959 | 2011-02-18 21:13:05 +0000 | [diff] [blame] | 5268 | { | 
|  | 5269 | #if 0 | 
|  | 5270 | // ARM pseudo code... | 
|  | 5271 | if ConditionPassed() then | 
|  | 5272 | EncodingSpecificOperations(); | 
|  | 5273 | shifted = Shift(R[m], shift_t, shift_n, APSR.C); | 
|  | 5274 | (result, carry, overflow) = AddWithCarry(R[n], shifted, APSR.C); | 
|  | 5275 | if d == 15 then         // Can only occur for ARM encoding | 
|  | 5276 | ALUWritePC(result); // setflags is always FALSE here | 
|  | 5277 | else | 
|  | 5278 | R[d] = result; | 
|  | 5279 | if setflags then | 
|  | 5280 | APSR.N = result<31>; | 
|  | 5281 | APSR.Z = IsZeroBit(result); | 
|  | 5282 | APSR.C = carry; | 
|  | 5283 | APSR.V = overflow; | 
|  | 5284 | #endif | 
|  | 5285 |  | 
|  | 5286 | bool success = false; | 
| Johnny Chen | 157b959 | 2011-02-18 21:13:05 +0000 | [diff] [blame] | 5287 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 5288 | if (ConditionPassed(opcode)) | 
| Johnny Chen | 157b959 | 2011-02-18 21:13:05 +0000 | [diff] [blame] | 5289 | { | 
|  | 5290 | uint32_t Rd, Rn, Rm; | 
|  | 5291 | ARM_ShifterType shift_t; | 
|  | 5292 | uint32_t shift_n; // the shift applied to the value read from Rm | 
|  | 5293 | bool setflags; | 
|  | 5294 | switch (encoding) | 
|  | 5295 | { | 
|  | 5296 | case eEncodingT1: | 
|  | 5297 | Rd = Rn = Bits32(opcode, 2, 0); | 
|  | 5298 | Rm = Bits32(opcode, 5, 3); | 
|  | 5299 | setflags = !InITBlock(); | 
|  | 5300 | shift_t = SRType_LSL; | 
|  | 5301 | shift_n = 0; | 
| Johnny Chen | ed32e7c | 2011-02-22 23:42:58 +0000 | [diff] [blame] | 5302 | break; | 
| Johnny Chen | 157b959 | 2011-02-18 21:13:05 +0000 | [diff] [blame] | 5303 | case eEncodingT2: | 
|  | 5304 | Rd = Bits32(opcode, 11, 8); | 
|  | 5305 | Rn = Bits32(opcode, 19, 16); | 
|  | 5306 | Rm = Bits32(opcode, 3, 0); | 
|  | 5307 | setflags = BitIsSet(opcode, 20); | 
| Johnny Chen | 3dd0605 | 2011-02-22 21:17:52 +0000 | [diff] [blame] | 5308 | shift_n = DecodeImmShiftThumb(opcode, shift_t); | 
| Johnny Chen | 157b959 | 2011-02-18 21:13:05 +0000 | [diff] [blame] | 5309 | if (BadReg(Rd) || BadReg(Rn) || BadReg(Rm)) | 
|  | 5310 | return false; | 
|  | 5311 | break; | 
|  | 5312 | case eEncodingA1: | 
|  | 5313 | Rd = Bits32(opcode, 15, 12); | 
|  | 5314 | Rn = Bits32(opcode, 19, 16); | 
|  | 5315 | Rm = Bits32(opcode, 3, 0); | 
|  | 5316 | setflags = BitIsSet(opcode, 20); | 
| Johnny Chen | 3dd0605 | 2011-02-22 21:17:52 +0000 | [diff] [blame] | 5317 | shift_n = DecodeImmShiftARM(opcode, shift_t); | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 5318 |  | 
| Johnny Chen | 157b959 | 2011-02-18 21:13:05 +0000 | [diff] [blame] | 5319 | if (Rd == 15 && setflags) | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 5320 | return EmulateSUBSPcLrEtc (opcode, encoding); | 
| Johnny Chen | 157b959 | 2011-02-18 21:13:05 +0000 | [diff] [blame] | 5321 | break; | 
|  | 5322 | default: | 
|  | 5323 | return false; | 
|  | 5324 | } | 
|  | 5325 |  | 
|  | 5326 | // Read the first operand. | 
|  | 5327 | int32_t val1 = ReadCoreReg(Rn, &success); | 
|  | 5328 | if (!success) | 
|  | 5329 | return false; | 
|  | 5330 |  | 
|  | 5331 | // Read the second operand. | 
|  | 5332 | int32_t val2 = ReadCoreReg(Rm, &success); | 
|  | 5333 | if (!success) | 
|  | 5334 | return false; | 
|  | 5335 |  | 
| Johnny Chen | a4438a7 | 2011-06-02 22:50:51 +0000 | [diff] [blame] | 5336 | uint32_t shifted = Shift(val2, shift_t, shift_n, APSR_C, &success); | 
|  | 5337 | if (!success) | 
|  | 5338 | return false; | 
| Johnny Chen | 157b959 | 2011-02-18 21:13:05 +0000 | [diff] [blame] | 5339 | AddWithCarryResult res = AddWithCarry(val1, shifted, APSR_C); | 
|  | 5340 |  | 
|  | 5341 | EmulateInstruction::Context context; | 
|  | 5342 | context.type = EmulateInstruction::eContextImmediate; | 
|  | 5343 | context.SetNoArgs (); | 
|  | 5344 |  | 
|  | 5345 | if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, res.carry_out, res.overflow)) | 
|  | 5346 | return false; | 
|  | 5347 | } | 
|  | 5348 | return true; | 
|  | 5349 | } | 
|  | 5350 |  | 
| Johnny Chen | a695f95 | 2011-02-23 21:24:25 +0000 | [diff] [blame] | 5351 | // This instruction adds an immediate value to the PC value to form a PC-relative address, | 
|  | 5352 | // and writes the result to the destination register. | 
|  | 5353 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 5354 | EmulateInstructionARM::EmulateADR (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | a695f95 | 2011-02-23 21:24:25 +0000 | [diff] [blame] | 5355 | { | 
|  | 5356 | #if 0 | 
|  | 5357 | // ARM pseudo code... | 
|  | 5358 | if ConditionPassed() then | 
|  | 5359 | EncodingSpecificOperations(); | 
|  | 5360 | result = if add then (Align(PC,4) + imm32) else (Align(PC,4) - imm32); | 
|  | 5361 | if d == 15 then         // Can only occur for ARM encodings | 
|  | 5362 | ALUWritePC(result); | 
|  | 5363 | else | 
|  | 5364 | R[d] = result; | 
|  | 5365 | #endif | 
|  | 5366 |  | 
|  | 5367 | bool success = false; | 
| Johnny Chen | a695f95 | 2011-02-23 21:24:25 +0000 | [diff] [blame] | 5368 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 5369 | if (ConditionPassed(opcode)) | 
| Johnny Chen | a695f95 | 2011-02-23 21:24:25 +0000 | [diff] [blame] | 5370 | { | 
|  | 5371 | uint32_t Rd; | 
|  | 5372 | uint32_t imm32; // the immediate value to be added/subtracted to/from the PC | 
|  | 5373 | bool add; | 
|  | 5374 | switch (encoding) | 
|  | 5375 | { | 
|  | 5376 | case eEncodingT1: | 
|  | 5377 | Rd = Bits32(opcode, 10, 8); | 
|  | 5378 | imm32 = ThumbImm8Scaled(opcode); // imm32 = ZeroExtend(imm8:'00', 32) | 
|  | 5379 | break; | 
|  | 5380 | case eEncodingT2: | 
|  | 5381 | case eEncodingT3: | 
|  | 5382 | Rd = Bits32(opcode, 11, 8); | 
|  | 5383 | imm32 = ThumbImm12(opcode); // imm32 = ZeroExtend(i:imm3:imm8, 32) | 
|  | 5384 | add = (Bits32(opcode, 24, 21) == 0); // 0b0000 => ADD; 0b0101 => SUB | 
|  | 5385 | if (BadReg(Rd)) | 
|  | 5386 | return false; | 
|  | 5387 | break; | 
|  | 5388 | case eEncodingA1: | 
|  | 5389 | case eEncodingA2: | 
|  | 5390 | Rd = Bits32(opcode, 15, 12); | 
|  | 5391 | imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12) | 
|  | 5392 | add = (Bits32(opcode, 24, 21) == 0x4); // 0b0100 => ADD; 0b0010 => SUB | 
|  | 5393 | break; | 
|  | 5394 | default: | 
|  | 5395 | return false; | 
|  | 5396 | } | 
|  | 5397 |  | 
|  | 5398 | // Read the PC value. | 
|  | 5399 | uint32_t pc = ReadCoreReg(PC_REG, &success); | 
|  | 5400 | if (!success) | 
|  | 5401 | return false; | 
|  | 5402 |  | 
|  | 5403 | uint32_t result = (add ? Align(pc, 4) + imm32 : Align(pc, 4) - imm32); | 
|  | 5404 |  | 
|  | 5405 | EmulateInstruction::Context context; | 
|  | 5406 | context.type = EmulateInstruction::eContextImmediate; | 
|  | 5407 | context.SetNoArgs (); | 
|  | 5408 |  | 
|  | 5409 | if (!WriteCoreReg(context, result, Rd)) | 
|  | 5410 | return false; | 
|  | 5411 | } | 
|  | 5412 | return true; | 
|  | 5413 | } | 
|  | 5414 |  | 
| Johnny Chen | e97c0d5 | 2011-02-18 19:32:20 +0000 | [diff] [blame] | 5415 | // This instruction performs a bitwise AND of a register value and an immediate value, and writes the result | 
|  | 5416 | // to the destination register.  It can optionally update the condition flags based on the result. | 
|  | 5417 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 5418 | EmulateInstructionARM::EmulateANDImm (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | e97c0d5 | 2011-02-18 19:32:20 +0000 | [diff] [blame] | 5419 | { | 
|  | 5420 | #if 0 | 
|  | 5421 | // ARM pseudo code... | 
|  | 5422 | if ConditionPassed() then | 
|  | 5423 | EncodingSpecificOperations(); | 
|  | 5424 | result = R[n] AND imm32; | 
|  | 5425 | if d == 15 then         // Can only occur for ARM encoding | 
|  | 5426 | ALUWritePC(result); // setflags is always FALSE here | 
|  | 5427 | else | 
|  | 5428 | R[d] = result; | 
|  | 5429 | if setflags then | 
|  | 5430 | APSR.N = result<31>; | 
|  | 5431 | APSR.Z = IsZeroBit(result); | 
|  | 5432 | APSR.C = carry; | 
|  | 5433 | // APSR.V unchanged | 
|  | 5434 | #endif | 
|  | 5435 |  | 
|  | 5436 | bool success = false; | 
| Johnny Chen | e97c0d5 | 2011-02-18 19:32:20 +0000 | [diff] [blame] | 5437 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 5438 | if (ConditionPassed(opcode)) | 
| Johnny Chen | e97c0d5 | 2011-02-18 19:32:20 +0000 | [diff] [blame] | 5439 | { | 
|  | 5440 | uint32_t Rd, Rn; | 
|  | 5441 | uint32_t imm32; // the immediate value to be ANDed to the value obtained from Rn | 
|  | 5442 | bool setflags; | 
|  | 5443 | uint32_t carry; // the carry bit after ARM/Thumb Expand operation | 
|  | 5444 | switch (encoding) | 
|  | 5445 | { | 
|  | 5446 | case eEncodingT1: | 
|  | 5447 | Rd = Bits32(opcode, 11, 8); | 
|  | 5448 | Rn = Bits32(opcode, 19, 16); | 
|  | 5449 | setflags = BitIsSet(opcode, 20); | 
|  | 5450 | imm32 = ThumbExpandImm_C(opcode, APSR_C, carry); // (imm32, carry) = ThumbExpandImm(i:imm3:imm8, APSR.C) | 
| Johnny Chen | de3cce3 | 2011-02-21 21:24:49 +0000 | [diff] [blame] | 5451 | // if Rd == '1111' && S == '1' then SEE TST (immediate); | 
| Johnny Chen | e97c0d5 | 2011-02-18 19:32:20 +0000 | [diff] [blame] | 5452 | if (Rd == 15 && setflags) | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 5453 | return EmulateTSTImm(opcode, eEncodingT1); | 
| Johnny Chen | e97c0d5 | 2011-02-18 19:32:20 +0000 | [diff] [blame] | 5454 | if (Rd == 13 || (Rd == 15 && !setflags) || BadReg(Rn)) | 
|  | 5455 | return false; | 
|  | 5456 | break; | 
|  | 5457 | case eEncodingA1: | 
|  | 5458 | Rd = Bits32(opcode, 15, 12); | 
|  | 5459 | Rn = Bits32(opcode, 19, 16); | 
|  | 5460 | setflags = BitIsSet(opcode, 20); | 
|  | 5461 | imm32 = ARMExpandImm_C(opcode, APSR_C, carry); // (imm32, carry) = ARMExpandImm(imm12, APSR.C) | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 5462 |  | 
| Johnny Chen | e97c0d5 | 2011-02-18 19:32:20 +0000 | [diff] [blame] | 5463 | if (Rd == 15 && setflags) | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 5464 | return EmulateSUBSPcLrEtc (opcode, encoding); | 
| Johnny Chen | e97c0d5 | 2011-02-18 19:32:20 +0000 | [diff] [blame] | 5465 | break; | 
|  | 5466 | default: | 
|  | 5467 | return false; | 
|  | 5468 | } | 
|  | 5469 |  | 
| Johnny Chen | e97c0d5 | 2011-02-18 19:32:20 +0000 | [diff] [blame] | 5470 | // Read the first operand. | 
| Johnny Chen | 157b959 | 2011-02-18 21:13:05 +0000 | [diff] [blame] | 5471 | uint32_t val1 = ReadCoreReg(Rn, &success); | 
| Johnny Chen | e97c0d5 | 2011-02-18 19:32:20 +0000 | [diff] [blame] | 5472 | if (!success) | 
|  | 5473 | return false; | 
|  | 5474 |  | 
|  | 5475 | uint32_t result = val1 & imm32; | 
|  | 5476 |  | 
|  | 5477 | EmulateInstruction::Context context; | 
|  | 5478 | context.type = EmulateInstruction::eContextImmediate; | 
|  | 5479 | context.SetNoArgs (); | 
|  | 5480 |  | 
|  | 5481 | if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry)) | 
|  | 5482 | return false; | 
|  | 5483 | } | 
|  | 5484 | return true; | 
|  | 5485 | } | 
|  | 5486 |  | 
|  | 5487 | // This instruction performs a bitwise AND of a register value and an optionally-shifted register value, | 
|  | 5488 | // and writes the result to the destination register.  It can optionally update the condition flags | 
|  | 5489 | // based on the result. | 
|  | 5490 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 5491 | EmulateInstructionARM::EmulateANDReg (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | e97c0d5 | 2011-02-18 19:32:20 +0000 | [diff] [blame] | 5492 | { | 
|  | 5493 | #if 0 | 
|  | 5494 | // ARM pseudo code... | 
|  | 5495 | if ConditionPassed() then | 
|  | 5496 | EncodingSpecificOperations(); | 
|  | 5497 | (shifted, carry) = Shift_C(R[m], shift_t, shift_n, APSR.C); | 
|  | 5498 | result = R[n] AND shifted; | 
|  | 5499 | if d == 15 then         // Can only occur for ARM encoding | 
|  | 5500 | ALUWritePC(result); // setflags is always FALSE here | 
|  | 5501 | else | 
|  | 5502 | R[d] = result; | 
|  | 5503 | if setflags then | 
|  | 5504 | APSR.N = result<31>; | 
|  | 5505 | APSR.Z = IsZeroBit(result); | 
|  | 5506 | APSR.C = carry; | 
|  | 5507 | // APSR.V unchanged | 
|  | 5508 | #endif | 
|  | 5509 |  | 
|  | 5510 | bool success = false; | 
| Johnny Chen | e97c0d5 | 2011-02-18 19:32:20 +0000 | [diff] [blame] | 5511 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 5512 | if (ConditionPassed(opcode)) | 
| Johnny Chen | e97c0d5 | 2011-02-18 19:32:20 +0000 | [diff] [blame] | 5513 | { | 
|  | 5514 | uint32_t Rd, Rn, Rm; | 
|  | 5515 | ARM_ShifterType shift_t; | 
|  | 5516 | uint32_t shift_n; // the shift applied to the value read from Rm | 
|  | 5517 | bool setflags; | 
|  | 5518 | uint32_t carry; | 
|  | 5519 | switch (encoding) | 
|  | 5520 | { | 
|  | 5521 | case eEncodingT1: | 
|  | 5522 | Rd = Rn = Bits32(opcode, 2, 0); | 
|  | 5523 | Rm = Bits32(opcode, 5, 3); | 
|  | 5524 | setflags = !InITBlock(); | 
|  | 5525 | shift_t = SRType_LSL; | 
|  | 5526 | shift_n = 0; | 
| Johnny Chen | ed32e7c | 2011-02-22 23:42:58 +0000 | [diff] [blame] | 5527 | break; | 
| Johnny Chen | e97c0d5 | 2011-02-18 19:32:20 +0000 | [diff] [blame] | 5528 | case eEncodingT2: | 
|  | 5529 | Rd = Bits32(opcode, 11, 8); | 
|  | 5530 | Rn = Bits32(opcode, 19, 16); | 
|  | 5531 | Rm = Bits32(opcode, 3, 0); | 
|  | 5532 | setflags = BitIsSet(opcode, 20); | 
| Johnny Chen | 3dd0605 | 2011-02-22 21:17:52 +0000 | [diff] [blame] | 5533 | shift_n = DecodeImmShiftThumb(opcode, shift_t); | 
| Johnny Chen | de3cce3 | 2011-02-21 21:24:49 +0000 | [diff] [blame] | 5534 | // if Rd == '1111' && S == '1' then SEE TST (register); | 
| Johnny Chen | e97c0d5 | 2011-02-18 19:32:20 +0000 | [diff] [blame] | 5535 | if (Rd == 15 && setflags) | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 5536 | return EmulateTSTReg(opcode, eEncodingT2); | 
| Johnny Chen | e97c0d5 | 2011-02-18 19:32:20 +0000 | [diff] [blame] | 5537 | if (Rd == 13 || (Rd == 15 && !setflags) || BadReg(Rn) || BadReg(Rm)) | 
|  | 5538 | return false; | 
|  | 5539 | break; | 
|  | 5540 | case eEncodingA1: | 
|  | 5541 | Rd = Bits32(opcode, 15, 12); | 
|  | 5542 | Rn = Bits32(opcode, 19, 16); | 
|  | 5543 | Rm = Bits32(opcode, 3, 0); | 
|  | 5544 | setflags = BitIsSet(opcode, 20); | 
| Johnny Chen | 3dd0605 | 2011-02-22 21:17:52 +0000 | [diff] [blame] | 5545 | shift_n = DecodeImmShiftARM(opcode, shift_t); | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 5546 |  | 
| Johnny Chen | e97c0d5 | 2011-02-18 19:32:20 +0000 | [diff] [blame] | 5547 | if (Rd == 15 && setflags) | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 5548 | return EmulateSUBSPcLrEtc (opcode, encoding); | 
| Johnny Chen | e97c0d5 | 2011-02-18 19:32:20 +0000 | [diff] [blame] | 5549 | break; | 
|  | 5550 | default: | 
|  | 5551 | return false; | 
|  | 5552 | } | 
|  | 5553 |  | 
| Johnny Chen | e97c0d5 | 2011-02-18 19:32:20 +0000 | [diff] [blame] | 5554 | // Read the first operand. | 
| Johnny Chen | 157b959 | 2011-02-18 21:13:05 +0000 | [diff] [blame] | 5555 | uint32_t val1 = ReadCoreReg(Rn, &success); | 
| Johnny Chen | e97c0d5 | 2011-02-18 19:32:20 +0000 | [diff] [blame] | 5556 | if (!success) | 
|  | 5557 | return false; | 
|  | 5558 |  | 
|  | 5559 | // Read the second operand. | 
| Johnny Chen | 157b959 | 2011-02-18 21:13:05 +0000 | [diff] [blame] | 5560 | uint32_t val2 = ReadCoreReg(Rm, &success); | 
| Johnny Chen | e97c0d5 | 2011-02-18 19:32:20 +0000 | [diff] [blame] | 5561 | if (!success) | 
|  | 5562 | return false; | 
|  | 5563 |  | 
| Johnny Chen | a4438a7 | 2011-06-02 22:50:51 +0000 | [diff] [blame] | 5564 | uint32_t shifted = Shift_C(val2, shift_t, shift_n, APSR_C, carry, &success); | 
|  | 5565 | if (!success) | 
|  | 5566 | return false; | 
| Johnny Chen | e97c0d5 | 2011-02-18 19:32:20 +0000 | [diff] [blame] | 5567 | uint32_t result = val1 & shifted; | 
|  | 5568 |  | 
|  | 5569 | EmulateInstruction::Context context; | 
|  | 5570 | context.type = EmulateInstruction::eContextImmediate; | 
|  | 5571 | context.SetNoArgs (); | 
|  | 5572 |  | 
|  | 5573 | if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry)) | 
|  | 5574 | return false; | 
|  | 5575 | } | 
|  | 5576 | return true; | 
|  | 5577 | } | 
|  | 5578 |  | 
| Johnny Chen | b9f02cf | 2011-02-24 01:15:17 +0000 | [diff] [blame] | 5579 | // Bitwise Bit Clear (immediate) performs a bitwise AND of a register value and the complement of an | 
|  | 5580 | // immediate value, and writes the result to the destination register.  It can optionally update the | 
|  | 5581 | // condition flags based on the result. | 
|  | 5582 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 5583 | EmulateInstructionARM::EmulateBICImm (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | b9f02cf | 2011-02-24 01:15:17 +0000 | [diff] [blame] | 5584 | { | 
|  | 5585 | #if 0 | 
|  | 5586 | // ARM pseudo code... | 
|  | 5587 | if ConditionPassed() then | 
|  | 5588 | EncodingSpecificOperations(); | 
|  | 5589 | result = R[n] AND NOT(imm32); | 
|  | 5590 | if d == 15 then         // Can only occur for ARM encoding | 
|  | 5591 | ALUWritePC(result); // setflags is always FALSE here | 
|  | 5592 | else | 
|  | 5593 | R[d] = result; | 
|  | 5594 | if setflags then | 
|  | 5595 | APSR.N = result<31>; | 
|  | 5596 | APSR.Z = IsZeroBit(result); | 
|  | 5597 | APSR.C = carry; | 
|  | 5598 | // APSR.V unchanged | 
|  | 5599 | #endif | 
|  | 5600 |  | 
|  | 5601 | bool success = false; | 
| Johnny Chen | b9f02cf | 2011-02-24 01:15:17 +0000 | [diff] [blame] | 5602 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 5603 | if (ConditionPassed(opcode)) | 
| Johnny Chen | b9f02cf | 2011-02-24 01:15:17 +0000 | [diff] [blame] | 5604 | { | 
|  | 5605 | uint32_t Rd, Rn; | 
|  | 5606 | uint32_t imm32; // the immediate value to be bitwise inverted and ANDed to the value obtained from Rn | 
|  | 5607 | bool setflags; | 
|  | 5608 | uint32_t carry; // the carry bit after ARM/Thumb Expand operation | 
|  | 5609 | switch (encoding) | 
|  | 5610 | { | 
|  | 5611 | case eEncodingT1: | 
|  | 5612 | Rd = Bits32(opcode, 11, 8); | 
|  | 5613 | Rn = Bits32(opcode, 19, 16); | 
|  | 5614 | setflags = BitIsSet(opcode, 20); | 
|  | 5615 | imm32 = ThumbExpandImm_C(opcode, APSR_C, carry); // (imm32, carry) = ThumbExpandImm(i:imm3:imm8, APSR.C) | 
|  | 5616 | if (BadReg(Rd) || BadReg(Rn)) | 
|  | 5617 | return false; | 
|  | 5618 | break; | 
|  | 5619 | case eEncodingA1: | 
|  | 5620 | Rd = Bits32(opcode, 15, 12); | 
|  | 5621 | Rn = Bits32(opcode, 19, 16); | 
|  | 5622 | setflags = BitIsSet(opcode, 20); | 
|  | 5623 | imm32 = ARMExpandImm_C(opcode, APSR_C, carry); // (imm32, carry) = ARMExpandImm(imm12, APSR.C) | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 5624 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 5625 | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related instructions; | 
| Johnny Chen | b9f02cf | 2011-02-24 01:15:17 +0000 | [diff] [blame] | 5626 | if (Rd == 15 && setflags) | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 5627 | return EmulateSUBSPcLrEtc (opcode, encoding); | 
| Johnny Chen | b9f02cf | 2011-02-24 01:15:17 +0000 | [diff] [blame] | 5628 | break; | 
|  | 5629 | default: | 
|  | 5630 | return false; | 
|  | 5631 | } | 
|  | 5632 |  | 
|  | 5633 | // Read the first operand. | 
|  | 5634 | uint32_t val1 = ReadCoreReg(Rn, &success); | 
|  | 5635 | if (!success) | 
|  | 5636 | return false; | 
|  | 5637 |  | 
|  | 5638 | uint32_t result = val1 & ~imm32; | 
|  | 5639 |  | 
|  | 5640 | EmulateInstruction::Context context; | 
|  | 5641 | context.type = EmulateInstruction::eContextImmediate; | 
|  | 5642 | context.SetNoArgs (); | 
|  | 5643 |  | 
|  | 5644 | if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry)) | 
|  | 5645 | return false; | 
|  | 5646 | } | 
|  | 5647 | return true; | 
|  | 5648 | } | 
|  | 5649 |  | 
|  | 5650 | // Bitwise Bit Clear (register) performs a bitwise AND of a register value and the complement of an | 
|  | 5651 | // optionally-shifted register value, and writes the result to the destination register. | 
|  | 5652 | // It can optionally update the condition flags based on the result. | 
|  | 5653 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 5654 | EmulateInstructionARM::EmulateBICReg (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | b9f02cf | 2011-02-24 01:15:17 +0000 | [diff] [blame] | 5655 | { | 
|  | 5656 | #if 0 | 
|  | 5657 | // ARM pseudo code... | 
|  | 5658 | if ConditionPassed() then | 
|  | 5659 | EncodingSpecificOperations(); | 
|  | 5660 | (shifted, carry) = Shift_C(R[m], shift_t, shift_n, APSR.C); | 
|  | 5661 | result = R[n] AND NOT(shifted); | 
|  | 5662 | if d == 15 then         // Can only occur for ARM encoding | 
|  | 5663 | ALUWritePC(result); // setflags is always FALSE here | 
|  | 5664 | else | 
|  | 5665 | R[d] = result; | 
|  | 5666 | if setflags then | 
|  | 5667 | APSR.N = result<31>; | 
|  | 5668 | APSR.Z = IsZeroBit(result); | 
|  | 5669 | APSR.C = carry; | 
|  | 5670 | // APSR.V unchanged | 
|  | 5671 | #endif | 
|  | 5672 |  | 
|  | 5673 | bool success = false; | 
| Johnny Chen | b9f02cf | 2011-02-24 01:15:17 +0000 | [diff] [blame] | 5674 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 5675 | if (ConditionPassed(opcode)) | 
| Johnny Chen | b9f02cf | 2011-02-24 01:15:17 +0000 | [diff] [blame] | 5676 | { | 
|  | 5677 | uint32_t Rd, Rn, Rm; | 
|  | 5678 | ARM_ShifterType shift_t; | 
|  | 5679 | uint32_t shift_n; // the shift applied to the value read from Rm | 
|  | 5680 | bool setflags; | 
|  | 5681 | uint32_t carry; | 
|  | 5682 | switch (encoding) | 
|  | 5683 | { | 
|  | 5684 | case eEncodingT1: | 
|  | 5685 | Rd = Rn = Bits32(opcode, 2, 0); | 
|  | 5686 | Rm = Bits32(opcode, 5, 3); | 
|  | 5687 | setflags = !InITBlock(); | 
|  | 5688 | shift_t = SRType_LSL; | 
|  | 5689 | shift_n = 0; | 
|  | 5690 | break; | 
|  | 5691 | case eEncodingT2: | 
|  | 5692 | Rd = Bits32(opcode, 11, 8); | 
|  | 5693 | Rn = Bits32(opcode, 19, 16); | 
|  | 5694 | Rm = Bits32(opcode, 3, 0); | 
|  | 5695 | setflags = BitIsSet(opcode, 20); | 
|  | 5696 | shift_n = DecodeImmShiftThumb(opcode, shift_t); | 
|  | 5697 | if (BadReg(Rd) || BadReg(Rn) || BadReg(Rm)) | 
|  | 5698 | return false; | 
|  | 5699 | break; | 
|  | 5700 | case eEncodingA1: | 
|  | 5701 | Rd = Bits32(opcode, 15, 12); | 
|  | 5702 | Rn = Bits32(opcode, 19, 16); | 
|  | 5703 | Rm = Bits32(opcode, 3, 0); | 
|  | 5704 | setflags = BitIsSet(opcode, 20); | 
|  | 5705 | shift_n = DecodeImmShiftARM(opcode, shift_t); | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 5706 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 5707 | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related instructions; | 
| Johnny Chen | b9f02cf | 2011-02-24 01:15:17 +0000 | [diff] [blame] | 5708 | if (Rd == 15 && setflags) | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 5709 | return EmulateSUBSPcLrEtc (opcode, encoding); | 
| Johnny Chen | b9f02cf | 2011-02-24 01:15:17 +0000 | [diff] [blame] | 5710 | break; | 
|  | 5711 | default: | 
|  | 5712 | return false; | 
|  | 5713 | } | 
|  | 5714 |  | 
|  | 5715 | // Read the first operand. | 
|  | 5716 | uint32_t val1 = ReadCoreReg(Rn, &success); | 
|  | 5717 | if (!success) | 
|  | 5718 | return false; | 
|  | 5719 |  | 
|  | 5720 | // Read the second operand. | 
|  | 5721 | uint32_t val2 = ReadCoreReg(Rm, &success); | 
|  | 5722 | if (!success) | 
|  | 5723 | return false; | 
|  | 5724 |  | 
| Johnny Chen | a4438a7 | 2011-06-02 22:50:51 +0000 | [diff] [blame] | 5725 | uint32_t shifted = Shift_C(val2, shift_t, shift_n, APSR_C, carry, &success); | 
|  | 5726 | if (!success) | 
|  | 5727 | return false; | 
| Johnny Chen | b9f02cf | 2011-02-24 01:15:17 +0000 | [diff] [blame] | 5728 | uint32_t result = val1 & ~shifted; | 
|  | 5729 |  | 
|  | 5730 | EmulateInstruction::Context context; | 
|  | 5731 | context.type = EmulateInstruction::eContextImmediate; | 
|  | 5732 | context.SetNoArgs (); | 
|  | 5733 |  | 
|  | 5734 | if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry)) | 
|  | 5735 | return false; | 
|  | 5736 | } | 
|  | 5737 | return true; | 
|  | 5738 | } | 
|  | 5739 |  | 
| Caroline Tice | 4d729c5 | 2011-02-18 00:55:53 +0000 | [diff] [blame] | 5740 | // LDR (immediate, ARM) calculates an address from a base register value and an immediate offset, loads a word | 
| Johnny Chen | e92b27c | 2011-02-18 01:26:39 +0000 | [diff] [blame] | 5741 | // from memory, and writes it to a register.  It can use offset, post-indexed, or pre-indexed addressing. | 
| Caroline Tice | 4d729c5 | 2011-02-18 00:55:53 +0000 | [diff] [blame] | 5742 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 5743 | EmulateInstructionARM::EmulateLDRImmediateARM (const uint32_t opcode, const ARMEncoding encoding) | 
| Caroline Tice | 4d729c5 | 2011-02-18 00:55:53 +0000 | [diff] [blame] | 5744 | { | 
|  | 5745 | #if 0 | 
|  | 5746 | if ConditionPassed() then | 
|  | 5747 | EncodingSpecificOperations(); | 
|  | 5748 | offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | 5749 | address = if index then offset_addr else R[n]; | 
|  | 5750 | data = MemU[address,4]; | 
|  | 5751 | if wback then R[n] = offset_addr; | 
|  | 5752 | if t == 15 then | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 5753 | if address<1:0> == '00' then LoadWritePC(data); else UNPREDICTABLE; | 
|  | 5754 | elsif UnalignedSupport() || address<1:0> = '00' then | 
| Caroline Tice | 4d729c5 | 2011-02-18 00:55:53 +0000 | [diff] [blame] | 5755 | R[t] = data; | 
|  | 5756 | else // Can only apply before ARMv7 | 
|  | 5757 | R[t] = ROR(data, 8*UInt(address<1:0>)); | 
|  | 5758 | #endif | 
|  | 5759 |  | 
|  | 5760 | bool success = false; | 
| Caroline Tice | 4d729c5 | 2011-02-18 00:55:53 +0000 | [diff] [blame] | 5761 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 5762 | if (ConditionPassed(opcode)) | 
| Caroline Tice | 4d729c5 | 2011-02-18 00:55:53 +0000 | [diff] [blame] | 5763 | { | 
|  | 5764 | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  | 5765 |  | 
|  | 5766 | uint32_t t; | 
|  | 5767 | uint32_t n; | 
|  | 5768 | uint32_t imm32; | 
|  | 5769 | bool index; | 
|  | 5770 | bool add; | 
|  | 5771 | bool wback; | 
|  | 5772 |  | 
|  | 5773 | switch (encoding) | 
|  | 5774 | { | 
|  | 5775 | case eEncodingA1: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 5776 | // if Rn == '1111' then SEE LDR (literal); | 
|  | 5777 | // if P == '0' && W == '1' then SEE LDRT; | 
|  | 5778 | // if Rn == '1101' && P == '0' && U == '1' && W == '0' && imm12 == '000000000100' then SEE POP; | 
| Caroline Tice | 4d729c5 | 2011-02-18 00:55:53 +0000 | [diff] [blame] | 5779 | // t == UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32); | 
|  | 5780 | t = Bits32 (opcode, 15, 12); | 
|  | 5781 | n = Bits32 (opcode, 19, 16); | 
|  | 5782 | imm32 = Bits32 (opcode, 11, 0); | 
|  | 5783 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 5784 | // index = (P == '1');	add = (U == '1');	wback = (P == '0') || (W == '1'); | 
|  | 5785 | index = BitIsSet (opcode, 24); | 
|  | 5786 | add = BitIsSet (opcode, 23); | 
|  | 5787 | wback = (BitIsClear (opcode, 24) || BitIsSet (opcode, 21)); | 
| Caroline Tice | 4d729c5 | 2011-02-18 00:55:53 +0000 | [diff] [blame] | 5788 |  | 
|  | 5789 | // if wback && n == t then UNPREDICTABLE; | 
|  | 5790 | if (wback && (n == t)) | 
|  | 5791 | return false; | 
|  | 5792 |  | 
|  | 5793 | break; | 
|  | 5794 |  | 
|  | 5795 | default: | 
|  | 5796 | return false; | 
|  | 5797 | } | 
|  | 5798 |  | 
|  | 5799 | addr_t address; | 
|  | 5800 | addr_t offset_addr; | 
| Caroline Tice | 8d681f5 | 2011-03-17 23:50:16 +0000 | [diff] [blame] | 5801 | addr_t base_address = ReadCoreReg (n, &success); | 
| Caroline Tice | 4d729c5 | 2011-02-18 00:55:53 +0000 | [diff] [blame] | 5802 | if (!success) | 
|  | 5803 | return false; | 
|  | 5804 |  | 
|  | 5805 | // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | 5806 | if (add) | 
| Caroline Tice | 8d681f5 | 2011-03-17 23:50:16 +0000 | [diff] [blame] | 5807 | offset_addr = base_address + imm32; | 
| Caroline Tice | 4d729c5 | 2011-02-18 00:55:53 +0000 | [diff] [blame] | 5808 | else | 
|  | 5809 | offset_addr = base_address - imm32; | 
|  | 5810 |  | 
|  | 5811 | // address = if index then offset_addr else R[n]; | 
|  | 5812 | if (index) | 
|  | 5813 | address = offset_addr; | 
|  | 5814 | else | 
|  | 5815 | address = base_address; | 
|  | 5816 |  | 
|  | 5817 | // data = MemU[address,4]; | 
|  | 5818 |  | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 5819 | RegisterInfo base_reg; | 
|  | 5820 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
| Caroline Tice | 4d729c5 | 2011-02-18 00:55:53 +0000 | [diff] [blame] | 5821 |  | 
|  | 5822 | EmulateInstruction::Context context; | 
|  | 5823 | context.type = eContextRegisterLoad; | 
|  | 5824 | context.SetRegisterPlusOffset (base_reg, address - base_address); | 
|  | 5825 |  | 
|  | 5826 | uint64_t data = MemURead (context, address, addr_byte_size, 0, &success); | 
|  | 5827 | if (!success) | 
|  | 5828 | return false; | 
|  | 5829 |  | 
|  | 5830 | // if wback then R[n] = offset_addr; | 
|  | 5831 | if (wback) | 
|  | 5832 | { | 
|  | 5833 | context.type = eContextAdjustBaseRegister; | 
|  | 5834 | context.SetAddress (offset_addr); | 
|  | 5835 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr)) | 
|  | 5836 | return false; | 
|  | 5837 | } | 
|  | 5838 |  | 
|  | 5839 | // if t == 15 then | 
|  | 5840 | if (t == 15) | 
|  | 5841 | { | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 5842 | // if address<1:0> == '00' then LoadWritePC(data); else UNPREDICTABLE; | 
| Caroline Tice | 4d729c5 | 2011-02-18 00:55:53 +0000 | [diff] [blame] | 5843 | if (BitIsClear (address, 1) && BitIsClear (address, 0)) | 
|  | 5844 | { | 
|  | 5845 | // LoadWritePC (data); | 
|  | 5846 | context.type = eContextRegisterLoad; | 
|  | 5847 | context.SetRegisterPlusOffset (base_reg, address - base_address); | 
|  | 5848 | LoadWritePC (context, data); | 
|  | 5849 | } | 
|  | 5850 | else | 
|  | 5851 | return false; | 
|  | 5852 | } | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 5853 | // elsif UnalignedSupport() || address<1:0> = '00' then | 
| Caroline Tice | 4d729c5 | 2011-02-18 00:55:53 +0000 | [diff] [blame] | 5854 | else if (UnalignedSupport() || (BitIsClear (address, 1) && BitIsClear (address, 0))) | 
|  | 5855 | { | 
|  | 5856 | // R[t] = data; | 
|  | 5857 | context.type = eContextRegisterLoad; | 
|  | 5858 | context.SetRegisterPlusOffset (base_reg, address - base_address); | 
|  | 5859 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, data)) | 
|  | 5860 | return false; | 
|  | 5861 | } | 
|  | 5862 | // else // Can only apply before ARMv7 | 
|  | 5863 | else | 
|  | 5864 | { | 
|  | 5865 | // R[t] = ROR(data, 8*UInt(address<1:0>)); | 
| Johnny Chen | a4438a7 | 2011-06-02 22:50:51 +0000 | [diff] [blame] | 5866 | data = ROR (data, Bits32 (address, 1, 0), &success); | 
|  | 5867 | if (!success) | 
|  | 5868 | return false; | 
| Caroline Tice | 4d729c5 | 2011-02-18 00:55:53 +0000 | [diff] [blame] | 5869 | context.type = eContextRegisterLoad; | 
|  | 5870 | context.SetImmediate (data); | 
|  | 5871 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, data)) | 
|  | 5872 | return false; | 
|  | 5873 | } | 
|  | 5874 |  | 
|  | 5875 | } | 
|  | 5876 | return true; | 
|  | 5877 | } | 
|  | 5878 |  | 
| Caroline Tice | fe47911 | 2011-02-18 18:52:37 +0000 | [diff] [blame] | 5879 | // LDR (register) calculates an address from a base register value and an offset register value, loads a word | 
|  | 5880 | // from memory, and writes it to a resgister.  The offset register value can optionally be shifted. | 
|  | 5881 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 5882 | EmulateInstructionARM::EmulateLDRRegister (const uint32_t opcode, const ARMEncoding encoding) | 
| Caroline Tice | fe47911 | 2011-02-18 18:52:37 +0000 | [diff] [blame] | 5883 | { | 
|  | 5884 | #if 0 | 
|  | 5885 | if ConditionPassed() then | 
|  | 5886 | EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | 5887 | offset = Shift(R[m], shift_t, shift_n, APSR.C); | 
|  | 5888 | offset_addr = if add then (R[n] + offset) else (R[n] - offset); | 
|  | 5889 | address = if index then offset_addr else R[n]; | 
|  | 5890 | data = MemU[address,4]; | 
|  | 5891 | if wback then R[n] = offset_addr; | 
|  | 5892 | if t == 15 then | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 5893 | if address<1:0> == '00' then LoadWritePC(data); else UNPREDICTABLE; | 
|  | 5894 | elsif UnalignedSupport() || address<1:0> = '00' then | 
| Caroline Tice | fe47911 | 2011-02-18 18:52:37 +0000 | [diff] [blame] | 5895 | R[t] = data; | 
|  | 5896 | else // Can only apply before ARMv7 | 
|  | 5897 | if CurrentInstrSet() == InstrSet_ARM then | 
|  | 5898 | R[t] = ROR(data, 8*UInt(address<1:0>)); | 
|  | 5899 | else | 
|  | 5900 | R[t] = bits(32) UNKNOWN; | 
|  | 5901 | #endif | 
|  | 5902 |  | 
|  | 5903 | bool success = false; | 
| Caroline Tice | fe47911 | 2011-02-18 18:52:37 +0000 | [diff] [blame] | 5904 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 5905 | if (ConditionPassed(opcode)) | 
| Caroline Tice | fe47911 | 2011-02-18 18:52:37 +0000 | [diff] [blame] | 5906 | { | 
|  | 5907 | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  | 5908 |  | 
|  | 5909 | uint32_t t; | 
|  | 5910 | uint32_t n; | 
|  | 5911 | uint32_t m; | 
|  | 5912 | bool index; | 
|  | 5913 | bool add; | 
|  | 5914 | bool wback; | 
|  | 5915 | ARM_ShifterType shift_t; | 
|  | 5916 | uint32_t shift_n; | 
|  | 5917 |  | 
|  | 5918 | switch (encoding) | 
|  | 5919 | { | 
|  | 5920 | case eEncodingT1: | 
|  | 5921 | // if CurrentInstrSet() == InstrSet_ThumbEE then SEE "Modified operation in ThumbEE"; | 
|  | 5922 | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); | 
|  | 5923 | t = Bits32 (opcode, 2, 0); | 
|  | 5924 | n = Bits32 (opcode, 5, 3); | 
|  | 5925 | m = Bits32 (opcode, 8, 6); | 
|  | 5926 |  | 
|  | 5927 | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | 5928 | index = true; | 
|  | 5929 | add = true; | 
|  | 5930 | wback = false; | 
|  | 5931 |  | 
|  | 5932 | // (shift_t, shift_n) = (SRType_LSL, 0); | 
|  | 5933 | shift_t = SRType_LSL; | 
|  | 5934 | shift_n = 0; | 
|  | 5935 |  | 
|  | 5936 | break; | 
|  | 5937 |  | 
|  | 5938 | case eEncodingT2: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 5939 | // if Rn == '1111' then SEE LDR (literal); | 
| Caroline Tice | fe47911 | 2011-02-18 18:52:37 +0000 | [diff] [blame] | 5940 | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); | 
|  | 5941 | t = Bits32 (opcode, 15, 12); | 
|  | 5942 | n = Bits32 (opcode, 19, 16); | 
|  | 5943 | m = Bits32 (opcode, 3, 0); | 
|  | 5944 |  | 
|  | 5945 | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | 5946 | index = true; | 
|  | 5947 | add = true; | 
|  | 5948 | wback = false; | 
|  | 5949 |  | 
|  | 5950 | // (shift_t, shift_n) = (SRType_LSL, UInt(imm2)); | 
|  | 5951 | shift_t = SRType_LSL; | 
|  | 5952 | shift_n = Bits32 (opcode, 5, 4); | 
|  | 5953 |  | 
|  | 5954 | // if BadReg(m) then UNPREDICTABLE; | 
|  | 5955 | if (BadReg (m)) | 
|  | 5956 | return false; | 
|  | 5957 |  | 
|  | 5958 | // if t == 15 && InITBlock() && !LastInITBlock() then UNPREDICTABLE; | 
|  | 5959 | if ((t == 15) && InITBlock() && !LastInITBlock()) | 
|  | 5960 | return false; | 
|  | 5961 |  | 
|  | 5962 | break; | 
|  | 5963 |  | 
|  | 5964 | case eEncodingA1: | 
|  | 5965 | { | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 5966 | // if P == '0' && W == '1' then SEE LDRT; | 
| Caroline Tice | fe47911 | 2011-02-18 18:52:37 +0000 | [diff] [blame] | 5967 | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); | 
|  | 5968 | t = Bits32 (opcode, 15, 12); | 
|  | 5969 | n = Bits32 (opcode, 19, 16); | 
|  | 5970 | m = Bits32 (opcode, 3, 0); | 
|  | 5971 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 5972 | // index = (P == '1');	add = (U == '1');	wback = (P == '0') || (W == '1'); | 
| Caroline Tice | fe47911 | 2011-02-18 18:52:37 +0000 | [diff] [blame] | 5973 | index = BitIsSet (opcode, 24); | 
|  | 5974 | add = BitIsSet (opcode, 23); | 
|  | 5975 | wback = (BitIsClear (opcode, 24) || BitIsSet (opcode, 21)); | 
|  | 5976 |  | 
|  | 5977 | // (shift_t, shift_n) = DecodeImmShift(type, imm5); | 
|  | 5978 | uint32_t type = Bits32 (opcode, 6, 5); | 
|  | 5979 | uint32_t imm5 = Bits32 (opcode, 11, 7); | 
|  | 5980 | shift_n = DecodeImmShift (type, imm5, shift_t); | 
|  | 5981 |  | 
|  | 5982 | // if m == 15 then UNPREDICTABLE; | 
|  | 5983 | if (m == 15) | 
|  | 5984 | return false; | 
|  | 5985 |  | 
|  | 5986 | // if wback && (n == 15 || n == t) then UNPREDICTABLE; | 
|  | 5987 | if (wback && ((n == 15) || (n == t))) | 
|  | 5988 | return false; | 
|  | 5989 | } | 
|  | 5990 | break; | 
|  | 5991 |  | 
|  | 5992 |  | 
|  | 5993 | default: | 
|  | 5994 | return false; | 
|  | 5995 | } | 
|  | 5996 |  | 
|  | 5997 | uint32_t Rm = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + m, 0, &success); | 
|  | 5998 | if (!success) | 
|  | 5999 | return false; | 
|  | 6000 |  | 
|  | 6001 | uint32_t Rn = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success); | 
|  | 6002 | if (!success) | 
|  | 6003 | return false; | 
|  | 6004 |  | 
|  | 6005 | addr_t offset_addr; | 
|  | 6006 | addr_t address; | 
|  | 6007 |  | 
|  | 6008 | // offset = Shift(R[m], shift_t, shift_n, APSR.C);   -- Note "The APSR is an application level alias for the CPSR". | 
| Johnny Chen | a4438a7 | 2011-06-02 22:50:51 +0000 | [diff] [blame] | 6009 | addr_t offset = Shift (Rm, shift_t, shift_n, Bit32 (m_opcode_cpsr, APSR_C), &success); | 
|  | 6010 | if (!success) | 
|  | 6011 | return false; | 
| Caroline Tice | fe47911 | 2011-02-18 18:52:37 +0000 | [diff] [blame] | 6012 |  | 
|  | 6013 | // offset_addr = if add then (R[n] + offset) else (R[n] - offset); | 
|  | 6014 | if (add) | 
|  | 6015 | offset_addr = Rn + offset; | 
|  | 6016 | else | 
|  | 6017 | offset_addr = Rn - offset; | 
|  | 6018 |  | 
|  | 6019 | // address = if index then offset_addr else R[n]; | 
|  | 6020 | if (index) | 
|  | 6021 | address = offset_addr; | 
|  | 6022 | else | 
|  | 6023 | address = Rn; | 
|  | 6024 |  | 
|  | 6025 | // data = MemU[address,4]; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 6026 | RegisterInfo base_reg; | 
|  | 6027 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
| Caroline Tice | fe47911 | 2011-02-18 18:52:37 +0000 | [diff] [blame] | 6028 |  | 
|  | 6029 | EmulateInstruction::Context context; | 
|  | 6030 | context.type = eContextRegisterLoad; | 
|  | 6031 | context.SetRegisterPlusOffset (base_reg, address - Rn); | 
|  | 6032 |  | 
|  | 6033 | uint64_t data = MemURead (context, address, addr_byte_size, 0, &success); | 
|  | 6034 | if (!success) | 
|  | 6035 | return false; | 
|  | 6036 |  | 
|  | 6037 | // if wback then R[n] = offset_addr; | 
|  | 6038 | if (wback) | 
|  | 6039 | { | 
|  | 6040 | context.type = eContextAdjustBaseRegister; | 
|  | 6041 | context.SetAddress (offset_addr); | 
|  | 6042 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr)) | 
|  | 6043 | return false; | 
|  | 6044 | } | 
|  | 6045 |  | 
|  | 6046 | // if t == 15 then | 
|  | 6047 | if (t == 15) | 
|  | 6048 | { | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 6049 | // if address<1:0> == '00' then LoadWritePC(data); else UNPREDICTABLE; | 
| Caroline Tice | fe47911 | 2011-02-18 18:52:37 +0000 | [diff] [blame] | 6050 | if (BitIsClear (address, 1) && BitIsClear (address, 0)) | 
|  | 6051 | { | 
|  | 6052 | context.type = eContextRegisterLoad; | 
|  | 6053 | context.SetRegisterPlusOffset (base_reg, address - Rn); | 
|  | 6054 | LoadWritePC (context, data); | 
|  | 6055 | } | 
|  | 6056 | else | 
|  | 6057 | return false; | 
|  | 6058 | } | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 6059 | // elsif UnalignedSupport() || address<1:0> = '00' then | 
| Caroline Tice | fe47911 | 2011-02-18 18:52:37 +0000 | [diff] [blame] | 6060 | else if (UnalignedSupport () || (BitIsClear (address, 1) && BitIsClear (address, 0))) | 
|  | 6061 | { | 
|  | 6062 | // R[t] = data; | 
|  | 6063 | context.type = eContextRegisterLoad; | 
|  | 6064 | context.SetRegisterPlusOffset (base_reg, address - Rn); | 
|  | 6065 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, data)) | 
|  | 6066 | return false; | 
|  | 6067 | } | 
|  | 6068 | else // Can only apply before ARMv7 | 
|  | 6069 | { | 
|  | 6070 | // if CurrentInstrSet() == InstrSet_ARM then | 
|  | 6071 | if (CurrentInstrSet () == eModeARM) | 
|  | 6072 | { | 
|  | 6073 | // R[t] = ROR(data, 8*UInt(address<1:0>)); | 
| Johnny Chen | a4438a7 | 2011-06-02 22:50:51 +0000 | [diff] [blame] | 6074 | data = ROR (data, Bits32 (address, 1, 0), &success); | 
|  | 6075 | if (!success) | 
|  | 6076 | return false; | 
| Caroline Tice | fe47911 | 2011-02-18 18:52:37 +0000 | [diff] [blame] | 6077 | context.type = eContextRegisterLoad; | 
|  | 6078 | context.SetImmediate (data); | 
|  | 6079 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, data)) | 
|  | 6080 | return false; | 
|  | 6081 | } | 
|  | 6082 | else | 
|  | 6083 | { | 
|  | 6084 | // R[t] = bits(32) UNKNOWN; | 
|  | 6085 | WriteBits32Unknown (t); | 
|  | 6086 | } | 
|  | 6087 | } | 
|  | 6088 | } | 
|  | 6089 | return true; | 
|  | 6090 | } | 
| Caroline Tice | 21b604b | 2011-02-18 21:06:04 +0000 | [diff] [blame] | 6091 |  | 
|  | 6092 | // LDRB (immediate, Thumb) | 
|  | 6093 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 6094 | EmulateInstructionARM::EmulateLDRBImmediate (const uint32_t opcode, const ARMEncoding encoding) | 
| Caroline Tice | 21b604b | 2011-02-18 21:06:04 +0000 | [diff] [blame] | 6095 | { | 
|  | 6096 | #if 0 | 
|  | 6097 | if ConditionPassed() then | 
|  | 6098 | EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | 6099 | offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | 6100 | address = if index then offset_addr else R[n]; | 
|  | 6101 | R[t] = ZeroExtend(MemU[address,1], 32); | 
|  | 6102 | if wback then R[n] = offset_addr; | 
|  | 6103 | #endif | 
|  | 6104 |  | 
|  | 6105 | bool success = false; | 
| Caroline Tice | 21b604b | 2011-02-18 21:06:04 +0000 | [diff] [blame] | 6106 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 6107 | if (ConditionPassed(opcode)) | 
| Caroline Tice | 21b604b | 2011-02-18 21:06:04 +0000 | [diff] [blame] | 6108 | { | 
|  | 6109 | uint32_t t; | 
|  | 6110 | uint32_t n; | 
|  | 6111 | uint32_t imm32; | 
|  | 6112 | bool index; | 
|  | 6113 | bool add; | 
|  | 6114 | bool wback; | 
|  | 6115 |  | 
|  | 6116 | // EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | 6117 | switch (encoding) | 
|  | 6118 | { | 
|  | 6119 | case eEncodingT1: | 
|  | 6120 | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm5, 32); | 
|  | 6121 | t = Bits32 (opcode, 2, 0); | 
|  | 6122 | n = Bits32 (opcode, 5, 3); | 
|  | 6123 | imm32 = Bits32 (opcode, 10, 6); | 
|  | 6124 |  | 
|  | 6125 | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | 6126 | index = true; | 
|  | 6127 | add = true; | 
|  | 6128 | wback= false; | 
|  | 6129 |  | 
|  | 6130 | break; | 
|  | 6131 |  | 
|  | 6132 | case eEncodingT2: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 6133 | // if Rt == '1111' then SEE PLD; | 
|  | 6134 | // if Rn == '1111' then SEE LDRB (literal); | 
| Caroline Tice | 21b604b | 2011-02-18 21:06:04 +0000 | [diff] [blame] | 6135 | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32); | 
|  | 6136 | t = Bits32 (opcode, 15, 12); | 
|  | 6137 | n = Bits32 (opcode, 19, 16); | 
|  | 6138 | imm32 = Bits32 (opcode, 11, 0); | 
|  | 6139 |  | 
|  | 6140 | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | 6141 | index = true; | 
|  | 6142 | add = true; | 
|  | 6143 | wback = false; | 
|  | 6144 |  | 
|  | 6145 | // if t == 13 then UNPREDICTABLE; | 
|  | 6146 | if (t == 13) | 
|  | 6147 | return false; | 
|  | 6148 |  | 
|  | 6149 | break; | 
|  | 6150 |  | 
|  | 6151 | case eEncodingT3: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 6152 | // if Rt == '1111' && P == '1' && U == '0' && W == '0' then SEE PLD; | 
|  | 6153 | // if Rn == '1111' then SEE LDRB (literal); | 
|  | 6154 | // if P == '1' && U == '1' && W == '0' then SEE LDRBT; | 
|  | 6155 | // if P == '0' && W == '0' then UNDEFINED; | 
| Caroline Tice | 21b604b | 2011-02-18 21:06:04 +0000 | [diff] [blame] | 6156 | if (BitIsClear (opcode, 10) && BitIsClear (opcode, 8)) | 
|  | 6157 | return false; | 
|  | 6158 |  | 
|  | 6159 | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32); | 
|  | 6160 | t = Bits32 (opcode, 15, 12); | 
|  | 6161 | n = Bits32 (opcode, 19, 16); | 
|  | 6162 | imm32 = Bits32 (opcode, 7, 0); | 
|  | 6163 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 6164 | // index = (P == '1'); add = (U == '1'); wback = (W == '1'); | 
| Caroline Tice | 21b604b | 2011-02-18 21:06:04 +0000 | [diff] [blame] | 6165 | index = BitIsSet (opcode, 10); | 
|  | 6166 | add = BitIsSet (opcode, 9); | 
|  | 6167 | wback = BitIsSet (opcode, 8); | 
|  | 6168 |  | 
|  | 6169 | // if BadReg(t) || (wback && n == t) then UNPREDICTABLE; | 
|  | 6170 | if (BadReg (t) || (wback && (n == t))) | 
|  | 6171 | return false; | 
|  | 6172 |  | 
|  | 6173 | break; | 
|  | 6174 |  | 
|  | 6175 | default: | 
|  | 6176 | return false; | 
|  | 6177 | } | 
|  | 6178 |  | 
|  | 6179 | uint32_t Rn = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success); | 
|  | 6180 | if (!success) | 
|  | 6181 | return false; | 
|  | 6182 |  | 
|  | 6183 | addr_t address; | 
|  | 6184 | addr_t offset_addr; | 
|  | 6185 |  | 
|  | 6186 | // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | 6187 | if (add) | 
|  | 6188 | offset_addr = Rn + imm32; | 
|  | 6189 | else | 
|  | 6190 | offset_addr = Rn - imm32; | 
|  | 6191 |  | 
|  | 6192 | // address = if index then offset_addr else R[n]; | 
|  | 6193 | if (index) | 
|  | 6194 | address = offset_addr; | 
|  | 6195 | else | 
|  | 6196 | address = Rn; | 
|  | 6197 |  | 
|  | 6198 | // R[t] = ZeroExtend(MemU[address,1], 32); | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 6199 | RegisterInfo base_reg; | 
|  | 6200 | RegisterInfo data_reg; | 
|  | 6201 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
|  | 6202 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + t, data_reg); | 
| Caroline Tice | 21b604b | 2011-02-18 21:06:04 +0000 | [diff] [blame] | 6203 |  | 
|  | 6204 | EmulateInstruction::Context context; | 
|  | 6205 | context.type = eContextRegisterLoad; | 
|  | 6206 | context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, address - Rn); | 
|  | 6207 |  | 
|  | 6208 | uint64_t data = MemURead (context, address, 1, 0, &success); | 
|  | 6209 | if (!success) | 
|  | 6210 | return false; | 
|  | 6211 |  | 
|  | 6212 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, data)) | 
|  | 6213 | return false; | 
|  | 6214 |  | 
|  | 6215 | // if wback then R[n] = offset_addr; | 
|  | 6216 | if (wback) | 
|  | 6217 | { | 
|  | 6218 | context.type = eContextAdjustBaseRegister; | 
|  | 6219 | context.SetAddress (offset_addr); | 
|  | 6220 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr)) | 
|  | 6221 | return false; | 
|  | 6222 | } | 
|  | 6223 | } | 
|  | 6224 | return true; | 
|  | 6225 | } | 
| Caroline Tice | f55261f | 2011-02-18 22:24:22 +0000 | [diff] [blame] | 6226 |  | 
|  | 6227 | // LDRB (literal) calculates an address from the PC value and an immediate offset, loads a byte from memory, | 
|  | 6228 | // zero-extends it to form a 32-bit word and writes it to a register. | 
|  | 6229 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 6230 | EmulateInstructionARM::EmulateLDRBLiteral (const uint32_t opcode, const ARMEncoding encoding) | 
| Caroline Tice | f55261f | 2011-02-18 22:24:22 +0000 | [diff] [blame] | 6231 | { | 
|  | 6232 | #if 0 | 
|  | 6233 | if ConditionPassed() then | 
|  | 6234 | EncodingSpecificOperations(); NullCheckIfThumbEE(15); | 
|  | 6235 | base = Align(PC,4); | 
|  | 6236 | address = if add then (base + imm32) else (base - imm32); | 
|  | 6237 | R[t] = ZeroExtend(MemU[address,1], 32); | 
|  | 6238 | #endif | 
|  | 6239 |  | 
|  | 6240 | bool success = false; | 
| Caroline Tice | f55261f | 2011-02-18 22:24:22 +0000 | [diff] [blame] | 6241 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 6242 | if (ConditionPassed(opcode)) | 
| Caroline Tice | f55261f | 2011-02-18 22:24:22 +0000 | [diff] [blame] | 6243 | { | 
|  | 6244 | uint32_t t; | 
|  | 6245 | uint32_t imm32; | 
|  | 6246 | bool add; | 
|  | 6247 | switch (encoding) | 
|  | 6248 | { | 
|  | 6249 | case eEncodingT1: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 6250 | // if Rt == '1111' then SEE PLD; | 
|  | 6251 | // t = UInt(Rt); imm32 = ZeroExtend(imm12, 32); add = (U == '1'); | 
| Caroline Tice | f55261f | 2011-02-18 22:24:22 +0000 | [diff] [blame] | 6252 | t = Bits32 (opcode, 15, 12); | 
|  | 6253 | imm32 = Bits32 (opcode, 11, 0); | 
|  | 6254 | add = BitIsSet (opcode, 23); | 
|  | 6255 |  | 
|  | 6256 | // if t == 13 then UNPREDICTABLE; | 
|  | 6257 | if (t == 13) | 
|  | 6258 | return false; | 
|  | 6259 |  | 
|  | 6260 | break; | 
|  | 6261 |  | 
|  | 6262 | case eEncodingA1: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 6263 | // t == UInt(Rt); imm32 = ZeroExtend(imm12, 32); add = (U == '1'); | 
| Caroline Tice | f55261f | 2011-02-18 22:24:22 +0000 | [diff] [blame] | 6264 | t = Bits32 (opcode, 15, 12); | 
|  | 6265 | imm32 = Bits32 (opcode, 11, 0); | 
|  | 6266 | add = BitIsSet (opcode, 23); | 
|  | 6267 |  | 
|  | 6268 | // if t == 15 then UNPREDICTABLE; | 
|  | 6269 | if (t == 15) | 
|  | 6270 | return false; | 
|  | 6271 | break; | 
|  | 6272 |  | 
|  | 6273 | default: | 
|  | 6274 | return false; | 
|  | 6275 | } | 
|  | 6276 |  | 
|  | 6277 | // base = Align(PC,4); | 
| Caroline Tice | 8d681f5 | 2011-03-17 23:50:16 +0000 | [diff] [blame] | 6278 | uint32_t pc_val = ReadCoreReg (PC_REG, &success); | 
| Caroline Tice | f55261f | 2011-02-18 22:24:22 +0000 | [diff] [blame] | 6279 | if (!success) | 
|  | 6280 | return false; | 
|  | 6281 |  | 
|  | 6282 | uint32_t base = AlignPC (pc_val); | 
|  | 6283 |  | 
|  | 6284 | addr_t address; | 
|  | 6285 | // address = if add then (base + imm32) else (base - imm32); | 
|  | 6286 | if (add) | 
|  | 6287 | address = base + imm32; | 
|  | 6288 | else | 
|  | 6289 | address = base - imm32; | 
|  | 6290 |  | 
|  | 6291 | // R[t] = ZeroExtend(MemU[address,1], 32); | 
|  | 6292 | EmulateInstruction::Context context; | 
|  | 6293 | context.type = eContextRelativeBranchImmediate; | 
|  | 6294 | context.SetImmediate (address - base); | 
|  | 6295 |  | 
|  | 6296 | uint64_t data = MemURead (context, address, 1, 0, &success); | 
|  | 6297 | if (!success) | 
|  | 6298 | return false; | 
|  | 6299 |  | 
|  | 6300 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, data)) | 
|  | 6301 | return false; | 
|  | 6302 | } | 
|  | 6303 | return true; | 
|  | 6304 | } | 
| Caroline Tice | 30fec12 | 2011-02-18 23:52:21 +0000 | [diff] [blame] | 6305 |  | 
|  | 6306 | // LDRB (register) calculates an address from a base register value and an offset rigister value, loads a byte from | 
|  | 6307 | // memory, zero-extends it to form a 32-bit word, and writes it to a register.  The offset register value can | 
|  | 6308 | // optionally be shifted. | 
|  | 6309 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 6310 | EmulateInstructionARM::EmulateLDRBRegister (const uint32_t opcode, const ARMEncoding encoding) | 
| Caroline Tice | 30fec12 | 2011-02-18 23:52:21 +0000 | [diff] [blame] | 6311 | { | 
|  | 6312 | #if 0 | 
|  | 6313 | if ConditionPassed() then | 
|  | 6314 | EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | 6315 | offset = Shift(R[m], shift_t, shift_n, APSR.C); | 
|  | 6316 | offset_addr = if add then (R[n] + offset) else (R[n] - offset); | 
|  | 6317 | address = if index then offset_addr else R[n]; | 
|  | 6318 | R[t] = ZeroExtend(MemU[address,1],32); | 
|  | 6319 | if wback then R[n] = offset_addr; | 
|  | 6320 | #endif | 
|  | 6321 |  | 
|  | 6322 | bool success = false; | 
| Caroline Tice | 30fec12 | 2011-02-18 23:52:21 +0000 | [diff] [blame] | 6323 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 6324 | if (ConditionPassed(opcode)) | 
| Caroline Tice | 30fec12 | 2011-02-18 23:52:21 +0000 | [diff] [blame] | 6325 | { | 
|  | 6326 | uint32_t t; | 
|  | 6327 | uint32_t n; | 
|  | 6328 | uint32_t m; | 
|  | 6329 | bool index; | 
|  | 6330 | bool add; | 
|  | 6331 | bool wback; | 
|  | 6332 | ARM_ShifterType shift_t; | 
|  | 6333 | uint32_t shift_n; | 
|  | 6334 |  | 
|  | 6335 | // EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | 6336 | switch (encoding) | 
|  | 6337 | { | 
|  | 6338 | case eEncodingT1: | 
|  | 6339 | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); | 
|  | 6340 | t = Bits32 (opcode, 2, 0); | 
|  | 6341 | n = Bits32 (opcode, 5, 3); | 
|  | 6342 | m = Bits32 (opcode, 8, 6); | 
|  | 6343 |  | 
|  | 6344 | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | 6345 | index = true; | 
|  | 6346 | add = true; | 
|  | 6347 | wback = false; | 
|  | 6348 |  | 
|  | 6349 | // (shift_t, shift_n) = (SRType_LSL, 0); | 
|  | 6350 | shift_t = SRType_LSL; | 
|  | 6351 | shift_n = 0; | 
|  | 6352 | break; | 
|  | 6353 |  | 
|  | 6354 | case eEncodingT2: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 6355 | // if Rt == '1111' then SEE PLD; | 
|  | 6356 | // if Rn == '1111' then SEE LDRB (literal); | 
| Caroline Tice | 30fec12 | 2011-02-18 23:52:21 +0000 | [diff] [blame] | 6357 | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); | 
|  | 6358 | t = Bits32 (opcode, 15, 12); | 
|  | 6359 | n = Bits32 (opcode, 19, 16); | 
|  | 6360 | m = Bits32 (opcode, 3, 0); | 
|  | 6361 |  | 
|  | 6362 | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | 6363 | index = true; | 
|  | 6364 | add = true; | 
|  | 6365 | wback = false; | 
|  | 6366 |  | 
|  | 6367 | // (shift_t, shift_n) = (SRType_LSL, UInt(imm2)); | 
|  | 6368 | shift_t = SRType_LSL; | 
|  | 6369 | shift_n = Bits32 (opcode, 5, 4); | 
|  | 6370 |  | 
|  | 6371 | // if t == 13 || BadReg(m) then UNPREDICTABLE; | 
|  | 6372 | if ((t == 13) || BadReg (m)) | 
|  | 6373 | return false; | 
|  | 6374 | break; | 
|  | 6375 |  | 
|  | 6376 | case eEncodingA1: | 
|  | 6377 | { | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 6378 | // if P == '0' && W == '1' then SEE LDRBT; | 
| Caroline Tice | 30fec12 | 2011-02-18 23:52:21 +0000 | [diff] [blame] | 6379 | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); | 
|  | 6380 | t = Bits32 (opcode, 15, 12); | 
|  | 6381 | n = Bits32 (opcode, 19, 16); | 
|  | 6382 | m = Bits32 (opcode, 3, 0); | 
|  | 6383 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 6384 | // index = (P == '1');	add = (U == '1');	wback = (P == '0') || (W == '1'); | 
| Caroline Tice | 30fec12 | 2011-02-18 23:52:21 +0000 | [diff] [blame] | 6385 | index = BitIsSet (opcode, 24); | 
|  | 6386 | add = BitIsSet (opcode, 23); | 
|  | 6387 | wback = (BitIsClear (opcode, 24) || BitIsSet (opcode, 21)); | 
|  | 6388 |  | 
|  | 6389 | // (shift_t, shift_n) = DecodeImmShift(type, imm5); | 
|  | 6390 | uint32_t type = Bits32 (opcode, 6, 5); | 
|  | 6391 | uint32_t imm5 = Bits32 (opcode, 11, 7); | 
|  | 6392 | shift_n = DecodeImmShift (type, imm5, shift_t); | 
|  | 6393 |  | 
|  | 6394 | // if t == 15 || m == 15 then UNPREDICTABLE; | 
|  | 6395 | if ((t == 15) || (m == 15)) | 
|  | 6396 | return false; | 
|  | 6397 |  | 
|  | 6398 | // if wback && (n == 15 || n == t) then UNPREDICTABLE; | 
|  | 6399 | if (wback && ((n == 15) || (n == t))) | 
|  | 6400 | return false; | 
|  | 6401 | } | 
|  | 6402 | break; | 
|  | 6403 |  | 
|  | 6404 | default: | 
|  | 6405 | return false; | 
|  | 6406 | } | 
|  | 6407 |  | 
|  | 6408 | addr_t offset_addr; | 
|  | 6409 | addr_t address; | 
|  | 6410 |  | 
|  | 6411 | // offset = Shift(R[m], shift_t, shift_n, APSR.C); | 
|  | 6412 | uint32_t Rm = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + m, 0, &success); | 
|  | 6413 | if (!success) | 
|  | 6414 | return false; | 
|  | 6415 |  | 
| Johnny Chen | a4438a7 | 2011-06-02 22:50:51 +0000 | [diff] [blame] | 6416 | addr_t offset = Shift (Rm, shift_t, shift_n, APSR_C, &success); | 
|  | 6417 | if (!success) | 
|  | 6418 | return false; | 
| Caroline Tice | 30fec12 | 2011-02-18 23:52:21 +0000 | [diff] [blame] | 6419 |  | 
|  | 6420 | // offset_addr = if add then (R[n] + offset) else (R[n] - offset); | 
|  | 6421 | uint32_t Rn = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success); | 
|  | 6422 | if (!success) | 
|  | 6423 | return false; | 
|  | 6424 |  | 
|  | 6425 | if (add) | 
|  | 6426 | offset_addr = Rn + offset; | 
|  | 6427 | else | 
|  | 6428 | offset_addr = Rn - offset; | 
|  | 6429 |  | 
|  | 6430 | // address = if index then offset_addr else R[n]; | 
|  | 6431 | if (index) | 
|  | 6432 | address = offset_addr; | 
|  | 6433 | else | 
|  | 6434 | address = Rn; | 
|  | 6435 |  | 
|  | 6436 | // R[t] = ZeroExtend(MemU[address,1],32); | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 6437 | RegisterInfo base_reg; | 
|  | 6438 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
| Caroline Tice | 30fec12 | 2011-02-18 23:52:21 +0000 | [diff] [blame] | 6439 |  | 
|  | 6440 | EmulateInstruction::Context context; | 
|  | 6441 | context.type = eContextRegisterLoad; | 
|  | 6442 | context.SetRegisterPlusOffset (base_reg, address - Rn); | 
|  | 6443 |  | 
|  | 6444 | uint64_t data = MemURead (context, address, 1, 0, &success); | 
|  | 6445 | if (!success) | 
|  | 6446 | return false; | 
|  | 6447 |  | 
|  | 6448 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, data)) | 
|  | 6449 | return false; | 
|  | 6450 |  | 
|  | 6451 | // if wback then R[n] = offset_addr; | 
|  | 6452 | if (wback) | 
|  | 6453 | { | 
|  | 6454 | context.type = eContextAdjustBaseRegister; | 
|  | 6455 | context.SetAddress (offset_addr); | 
|  | 6456 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr)) | 
|  | 6457 | return false; | 
|  | 6458 | } | 
|  | 6459 | } | 
|  | 6460 | return true; | 
|  | 6461 | } | 
| Caroline Tice | 0491b3b | 2011-02-28 22:39:58 +0000 | [diff] [blame] | 6462 |  | 
|  | 6463 | // LDRH (immediate, Thumb) calculates an address from a base register value and an immediate offset, loads a | 
|  | 6464 | // halfword from memory, zero-extends it to form a 32-bit word, and writes it to a register.  It can use offset, | 
|  | 6465 | // post-indexed, or pre-indexed addressing. | 
|  | 6466 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 6467 | EmulateInstructionARM::EmulateLDRHImmediate (const uint32_t opcode, const ARMEncoding encoding) | 
| Caroline Tice | 0491b3b | 2011-02-28 22:39:58 +0000 | [diff] [blame] | 6468 | { | 
|  | 6469 | #if 0 | 
|  | 6470 | if ConditionPassed() then | 
|  | 6471 | EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | 6472 | offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | 6473 | address = if index then offset_addr else R[n]; | 
|  | 6474 | data = MemU[address,2]; | 
|  | 6475 | if wback then R[n] = offset_addr; | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 6476 | if UnalignedSupport() || address<0> = '0' then | 
| Caroline Tice | 0491b3b | 2011-02-28 22:39:58 +0000 | [diff] [blame] | 6477 | R[t] = ZeroExtend(data, 32); | 
|  | 6478 | else // Can only apply before ARMv7 | 
|  | 6479 | R[t] = bits(32) UNKNOWN; | 
|  | 6480 | #endif | 
|  | 6481 |  | 
|  | 6482 |  | 
|  | 6483 | bool success = false; | 
| Caroline Tice | 0491b3b | 2011-02-28 22:39:58 +0000 | [diff] [blame] | 6484 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 6485 | if (ConditionPassed(opcode)) | 
| Caroline Tice | 0491b3b | 2011-02-28 22:39:58 +0000 | [diff] [blame] | 6486 | { | 
|  | 6487 | uint32_t t; | 
|  | 6488 | uint32_t n; | 
|  | 6489 | uint32_t imm32; | 
|  | 6490 | bool index; | 
|  | 6491 | bool add; | 
|  | 6492 | bool wback; | 
|  | 6493 |  | 
|  | 6494 | // EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | 6495 | switch (encoding) | 
|  | 6496 | { | 
|  | 6497 | case eEncodingT1: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 6498 | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm5:'0', 32); | 
| Caroline Tice | 0491b3b | 2011-02-28 22:39:58 +0000 | [diff] [blame] | 6499 | t = Bits32 (opcode, 2, 0); | 
|  | 6500 | n = Bits32 (opcode, 5, 3); | 
|  | 6501 | imm32 = Bits32 (opcode, 10, 6) << 1; | 
|  | 6502 |  | 
|  | 6503 | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | 6504 | index = true; | 
|  | 6505 | add = true; | 
|  | 6506 | wback = false; | 
|  | 6507 |  | 
|  | 6508 | break; | 
|  | 6509 |  | 
|  | 6510 | case eEncodingT2: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 6511 | // if Rt == '1111' then SEE "Unallocated memory hints"; | 
|  | 6512 | // if Rn == '1111' then SEE LDRH (literal); | 
| Caroline Tice | 0491b3b | 2011-02-28 22:39:58 +0000 | [diff] [blame] | 6513 | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32); | 
|  | 6514 | t = Bits32 (opcode, 15, 12); | 
|  | 6515 | n = Bits32 (opcode, 19, 16); | 
|  | 6516 | imm32 = Bits32 (opcode, 11, 0); | 
|  | 6517 |  | 
|  | 6518 | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | 6519 | index = true; | 
|  | 6520 | add = true; | 
|  | 6521 | wback = false; | 
|  | 6522 |  | 
|  | 6523 | // if t == 13 then UNPREDICTABLE; | 
|  | 6524 | if (t == 13) | 
|  | 6525 | return false; | 
|  | 6526 | break; | 
|  | 6527 |  | 
|  | 6528 | case eEncodingT3: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 6529 | // if Rn == '1111' then SEE LDRH (literal); | 
|  | 6530 | // if Rt == '1111' && P == '1' && U == '0' && W == '0' then SEE "Unallocated memory hints"; | 
|  | 6531 | // if P == '1' && U == '1' && W == '0' then SEE LDRHT; | 
|  | 6532 | // if P == '0' && W == '0' then UNDEFINED; | 
| Caroline Tice | 0491b3b | 2011-02-28 22:39:58 +0000 | [diff] [blame] | 6533 | if (BitIsClear (opcode, 10) && BitIsClear (opcode, 8)) | 
|  | 6534 | return false; | 
|  | 6535 |  | 
|  | 6536 | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32); | 
|  | 6537 | t = Bits32 (opcode, 15, 12); | 
|  | 6538 | n = Bits32 (opcode, 19, 16); | 
|  | 6539 | imm32 = Bits32 (opcode, 7, 0); | 
|  | 6540 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 6541 | // index = (P == '1'); add = (U == '1'); wback = (W == '1'); | 
| Caroline Tice | 0491b3b | 2011-02-28 22:39:58 +0000 | [diff] [blame] | 6542 | index = BitIsSet (opcode, 10); | 
|  | 6543 | add = BitIsSet (opcode, 9); | 
|  | 6544 | wback = BitIsSet (opcode, 8); | 
|  | 6545 |  | 
|  | 6546 | // if BadReg(t) || (wback && n == t) then UNPREDICTABLE; | 
|  | 6547 | if (BadReg (t) || (wback && (n == t))) | 
|  | 6548 | return false; | 
|  | 6549 | break; | 
|  | 6550 |  | 
|  | 6551 | default: | 
|  | 6552 | return false; | 
|  | 6553 | } | 
|  | 6554 |  | 
|  | 6555 | // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | 6556 | uint32_t Rn = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success); | 
|  | 6557 | if (!success) | 
|  | 6558 | return false; | 
|  | 6559 |  | 
|  | 6560 | addr_t offset_addr; | 
|  | 6561 | addr_t address; | 
|  | 6562 |  | 
|  | 6563 | if (add) | 
|  | 6564 | offset_addr = Rn + imm32; | 
|  | 6565 | else | 
|  | 6566 | offset_addr = Rn - imm32; | 
|  | 6567 |  | 
|  | 6568 | // address = if index then offset_addr else R[n]; | 
|  | 6569 | if (index) | 
|  | 6570 | address = offset_addr; | 
|  | 6571 | else | 
|  | 6572 | address = Rn; | 
|  | 6573 |  | 
|  | 6574 | // data = MemU[address,2]; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 6575 | RegisterInfo base_reg; | 
|  | 6576 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
| Caroline Tice | 0491b3b | 2011-02-28 22:39:58 +0000 | [diff] [blame] | 6577 |  | 
|  | 6578 | EmulateInstruction::Context context; | 
|  | 6579 | context.type = eContextRegisterLoad; | 
|  | 6580 | context.SetRegisterPlusOffset (base_reg, address - Rn); | 
|  | 6581 |  | 
|  | 6582 | uint64_t data = MemURead (context, address, 2, 0, &success); | 
|  | 6583 | if (!success) | 
|  | 6584 | return false; | 
|  | 6585 |  | 
|  | 6586 | // if wback then R[n] = offset_addr; | 
|  | 6587 | if (wback) | 
|  | 6588 | { | 
|  | 6589 | context.type = eContextAdjustBaseRegister; | 
|  | 6590 | context.SetAddress (offset_addr); | 
|  | 6591 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr)) | 
|  | 6592 | return false; | 
|  | 6593 | } | 
|  | 6594 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 6595 | // if UnalignedSupport() || address<0> = '0' then | 
| Caroline Tice | 0491b3b | 2011-02-28 22:39:58 +0000 | [diff] [blame] | 6596 | if (UnalignedSupport () || BitIsClear (address, 0)) | 
|  | 6597 | { | 
|  | 6598 | // R[t] = ZeroExtend(data, 32); | 
|  | 6599 | context.type = eContextRegisterLoad; | 
|  | 6600 | context.SetRegisterPlusOffset (base_reg, address - Rn); | 
|  | 6601 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, data)) | 
|  | 6602 | return false; | 
|  | 6603 | } | 
|  | 6604 | else // Can only apply before ARMv7 | 
|  | 6605 | { | 
|  | 6606 | // R[t] = bits(32) UNKNOWN; | 
|  | 6607 | WriteBits32Unknown (t); | 
|  | 6608 | } | 
|  | 6609 | } | 
|  | 6610 | return true; | 
|  | 6611 | } | 
| Caroline Tice | fe47911 | 2011-02-18 18:52:37 +0000 | [diff] [blame] | 6612 |  | 
| Caroline Tice | 952b538 | 2011-02-28 23:15:24 +0000 | [diff] [blame] | 6613 | // LDRH (literal) caculates an address from the PC value and an immediate offset, loads a halfword from memory, | 
|  | 6614 | // zero-extends it to form a 32-bit word, and writes it to a register. | 
|  | 6615 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 6616 | EmulateInstructionARM::EmulateLDRHLiteral (const uint32_t opcode, const ARMEncoding encoding) | 
| Caroline Tice | 952b538 | 2011-02-28 23:15:24 +0000 | [diff] [blame] | 6617 | { | 
|  | 6618 | #if 0 | 
|  | 6619 | if ConditionPassed() then | 
|  | 6620 | EncodingSpecificOperations(); NullCheckIfThumbEE(15); | 
|  | 6621 | base = Align(PC,4); | 
|  | 6622 | address = if add then (base + imm32) else (base - imm32); | 
|  | 6623 | data = MemU[address,2]; | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 6624 | if UnalignedSupport() || address<0> = '0' then | 
| Caroline Tice | 952b538 | 2011-02-28 23:15:24 +0000 | [diff] [blame] | 6625 | R[t] = ZeroExtend(data, 32); | 
|  | 6626 | else // Can only apply before ARMv7 | 
|  | 6627 | R[t] = bits(32) UNKNOWN; | 
|  | 6628 | #endif | 
| Caroline Tice | 0e6bc95 | 2011-03-01 18:00:42 +0000 | [diff] [blame] | 6629 |  | 
| Caroline Tice | 952b538 | 2011-02-28 23:15:24 +0000 | [diff] [blame] | 6630 | bool success = false; | 
| Caroline Tice | 952b538 | 2011-02-28 23:15:24 +0000 | [diff] [blame] | 6631 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 6632 | if (ConditionPassed(opcode)) | 
| Caroline Tice | 952b538 | 2011-02-28 23:15:24 +0000 | [diff] [blame] | 6633 | { | 
|  | 6634 | uint32_t t; | 
|  | 6635 | uint32_t imm32; | 
|  | 6636 | bool add; | 
|  | 6637 |  | 
|  | 6638 | // EncodingSpecificOperations(); NullCheckIfThumbEE(15); | 
|  | 6639 | switch (encoding) | 
|  | 6640 | { | 
|  | 6641 | case eEncodingT1: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 6642 | // if Rt == '1111' then SEE "Unallocated memory hints"; | 
|  | 6643 | // t = UInt(Rt); imm32 = ZeroExtend(imm12, 32); add = (U == '1'); | 
| Caroline Tice | 952b538 | 2011-02-28 23:15:24 +0000 | [diff] [blame] | 6644 | t = Bits32 (opcode, 15, 12); | 
|  | 6645 | imm32 = Bits32 (opcode, 11, 0); | 
|  | 6646 | add = BitIsSet (opcode, 23); | 
|  | 6647 |  | 
|  | 6648 | // if t == 13 then UNPREDICTABLE; | 
|  | 6649 | if (t == 13) | 
|  | 6650 | return false; | 
|  | 6651 |  | 
|  | 6652 | break; | 
|  | 6653 |  | 
|  | 6654 | case eEncodingA1: | 
|  | 6655 | { | 
|  | 6656 | uint32_t imm4H = Bits32 (opcode, 11, 8); | 
|  | 6657 | uint32_t imm4L = Bits32 (opcode, 3, 0); | 
|  | 6658 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 6659 | // t == UInt(Rt); imm32 = ZeroExtend(imm4H:imm4L, 32); add = (U == '1'); | 
| Caroline Tice | 952b538 | 2011-02-28 23:15:24 +0000 | [diff] [blame] | 6660 | t = Bits32 (opcode, 15, 12); | 
| Caroline Tice | 40b1a6c | 2011-03-03 00:07:02 +0000 | [diff] [blame] | 6661 | imm32 = (imm4H << 4) | imm4L; | 
| Caroline Tice | 952b538 | 2011-02-28 23:15:24 +0000 | [diff] [blame] | 6662 | add = BitIsSet (opcode, 23); | 
|  | 6663 |  | 
|  | 6664 | // if t == 15 then UNPREDICTABLE; | 
|  | 6665 | if (t == 15) | 
|  | 6666 | return false; | 
|  | 6667 | break; | 
|  | 6668 | } | 
|  | 6669 |  | 
|  | 6670 | default: | 
|  | 6671 | return false; | 
|  | 6672 | } | 
|  | 6673 |  | 
|  | 6674 | // base = Align(PC,4); | 
| Caroline Tice | 8d681f5 | 2011-03-17 23:50:16 +0000 | [diff] [blame] | 6675 | uint64_t pc_value = ReadCoreReg (PC_REG, &success); | 
| Caroline Tice | 952b538 | 2011-02-28 23:15:24 +0000 | [diff] [blame] | 6676 | if (!success) | 
|  | 6677 | return false; | 
|  | 6678 |  | 
|  | 6679 | addr_t base = AlignPC (pc_value); | 
|  | 6680 | addr_t address; | 
|  | 6681 |  | 
|  | 6682 | // address = if add then (base + imm32) else (base - imm32); | 
|  | 6683 | if (add) | 
|  | 6684 | address = base + imm32; | 
|  | 6685 | else | 
|  | 6686 | address = base - imm32; | 
|  | 6687 |  | 
|  | 6688 | // data = MemU[address,2]; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 6689 | RegisterInfo base_reg; | 
|  | 6690 | GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, base_reg); | 
| Caroline Tice | 952b538 | 2011-02-28 23:15:24 +0000 | [diff] [blame] | 6691 |  | 
|  | 6692 | EmulateInstruction::Context context; | 
|  | 6693 | context.type = eContextRegisterLoad; | 
|  | 6694 | context.SetRegisterPlusOffset (base_reg, address - base); | 
|  | 6695 |  | 
|  | 6696 | uint64_t data = MemURead (context, address, 2, 0, &success); | 
|  | 6697 | if (!success) | 
|  | 6698 | return false; | 
|  | 6699 |  | 
|  | 6700 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 6701 | // if UnalignedSupport() || address<0> = '0' then | 
| Caroline Tice | 952b538 | 2011-02-28 23:15:24 +0000 | [diff] [blame] | 6702 | if (UnalignedSupport () || BitIsClear (address, 0)) | 
|  | 6703 | { | 
|  | 6704 | // R[t] = ZeroExtend(data, 32); | 
|  | 6705 | context.type = eContextRegisterLoad; | 
|  | 6706 | context.SetRegisterPlusOffset (base_reg, address - base); | 
|  | 6707 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, data)) | 
|  | 6708 | return false; | 
|  | 6709 |  | 
|  | 6710 | } | 
|  | 6711 | else // Can only apply before ARMv7 | 
|  | 6712 | { | 
|  | 6713 | // R[t] = bits(32) UNKNOWN; | 
|  | 6714 | WriteBits32Unknown (t); | 
|  | 6715 | } | 
|  | 6716 | } | 
|  | 6717 | return true; | 
|  | 6718 | } | 
|  | 6719 |  | 
| Caroline Tice | 0e6bc95 | 2011-03-01 18:00:42 +0000 | [diff] [blame] | 6720 | // LDRH (literal) calculates an address from a base register value and an offset register value, loads a halfword | 
|  | 6721 | // from memory, zero-extends it to form a 32-bit word, and writes it to a register.  The offset register value can | 
|  | 6722 | // be shifted left by 0, 1, 2, or 3 bits. | 
|  | 6723 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 6724 | EmulateInstructionARM::EmulateLDRHRegister (const uint32_t opcode, const ARMEncoding encoding) | 
| Caroline Tice | 0e6bc95 | 2011-03-01 18:00:42 +0000 | [diff] [blame] | 6725 | { | 
|  | 6726 | #if 0 | 
|  | 6727 | if ConditionPassed() then | 
|  | 6728 | EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | 6729 | offset = Shift(R[m], shift_t, shift_n, APSR.C); | 
|  | 6730 | offset_addr = if add then (R[n] + offset) else (R[n] - offset); | 
|  | 6731 | address = if index then offset_addr else R[n]; | 
|  | 6732 | data = MemU[address,2]; | 
|  | 6733 | if wback then R[n] = offset_addr; | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 6734 | if UnalignedSupport() || address<0> = '0' then | 
| Caroline Tice | 0e6bc95 | 2011-03-01 18:00:42 +0000 | [diff] [blame] | 6735 | R[t] = ZeroExtend(data, 32); | 
|  | 6736 | else // Can only apply before ARMv7 | 
|  | 6737 | R[t] = bits(32) UNKNOWN; | 
|  | 6738 | #endif | 
|  | 6739 |  | 
|  | 6740 | bool success = false; | 
| Caroline Tice | 0e6bc95 | 2011-03-01 18:00:42 +0000 | [diff] [blame] | 6741 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 6742 | if (ConditionPassed(opcode)) | 
| Caroline Tice | 0e6bc95 | 2011-03-01 18:00:42 +0000 | [diff] [blame] | 6743 | { | 
|  | 6744 | uint32_t t; | 
|  | 6745 | uint32_t n; | 
|  | 6746 | uint32_t m; | 
|  | 6747 | bool index; | 
|  | 6748 | bool add; | 
|  | 6749 | bool wback; | 
|  | 6750 | ARM_ShifterType shift_t; | 
|  | 6751 | uint32_t shift_n; | 
|  | 6752 |  | 
|  | 6753 | // EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | 6754 | switch (encoding) | 
|  | 6755 | { | 
|  | 6756 | case eEncodingT1: | 
|  | 6757 | // if CurrentInstrSet() == InstrSet_ThumbEE then SEE "Modified operation in ThumbEE"; | 
|  | 6758 | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); | 
|  | 6759 | t = Bits32 (opcode, 2, 0); | 
|  | 6760 | n = Bits32 (opcode, 5, 3); | 
|  | 6761 | m = Bits32 (opcode, 8, 6); | 
|  | 6762 |  | 
|  | 6763 | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | 6764 | index = true; | 
|  | 6765 | add = true; | 
|  | 6766 | wback = false; | 
|  | 6767 |  | 
|  | 6768 | // (shift_t, shift_n) = (SRType_LSL, 0); | 
|  | 6769 | shift_t = SRType_LSL; | 
|  | 6770 | shift_n = 0; | 
|  | 6771 |  | 
|  | 6772 | break; | 
|  | 6773 |  | 
|  | 6774 | case eEncodingT2: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 6775 | // if Rn == '1111' then SEE LDRH (literal); | 
|  | 6776 | // if Rt == '1111' then SEE "Unallocated memory hints"; | 
| Caroline Tice | 0e6bc95 | 2011-03-01 18:00:42 +0000 | [diff] [blame] | 6777 | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); | 
|  | 6778 | t = Bits32 (opcode, 15, 12); | 
|  | 6779 | n = Bits32 (opcode, 19, 16); | 
|  | 6780 | m = Bits32 (opcode, 3, 0); | 
|  | 6781 |  | 
|  | 6782 | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | 6783 | index = true; | 
|  | 6784 | add = true; | 
|  | 6785 | wback = false; | 
|  | 6786 |  | 
|  | 6787 | // (shift_t, shift_n) = (SRType_LSL, UInt(imm2)); | 
|  | 6788 | shift_t = SRType_LSL; | 
|  | 6789 | shift_n = Bits32 (opcode, 5, 4); | 
|  | 6790 |  | 
|  | 6791 | // if t == 13 || BadReg(m) then UNPREDICTABLE; | 
|  | 6792 | if ((t == 13) || BadReg (m)) | 
|  | 6793 | return false; | 
|  | 6794 | break; | 
|  | 6795 |  | 
|  | 6796 | case eEncodingA1: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 6797 | // if P == '0' && W == '1' then SEE LDRHT; | 
| Caroline Tice | 0e6bc95 | 2011-03-01 18:00:42 +0000 | [diff] [blame] | 6798 | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); | 
|  | 6799 | t = Bits32 (opcode, 15, 12); | 
|  | 6800 | n = Bits32 (opcode, 19, 16); | 
|  | 6801 | m = Bits32 (opcode, 3, 0); | 
|  | 6802 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 6803 | // index = (P == '1');	add = (U == '1');	wback = (P == '0') || (W == '1'); | 
| Caroline Tice | 0e6bc95 | 2011-03-01 18:00:42 +0000 | [diff] [blame] | 6804 | index = BitIsSet (opcode, 24); | 
|  | 6805 | add = BitIsSet (opcode, 23); | 
|  | 6806 | wback = (BitIsClear (opcode, 24) || BitIsSet (opcode, 21)); | 
|  | 6807 |  | 
|  | 6808 | // (shift_t, shift_n) = (SRType_LSL, 0); | 
|  | 6809 | shift_t = SRType_LSL; | 
|  | 6810 | shift_n = 0; | 
|  | 6811 |  | 
|  | 6812 | // if t == 15 || m == 15 then UNPREDICTABLE; | 
|  | 6813 | if ((t == 15) || (m == 15)) | 
|  | 6814 | return false; | 
|  | 6815 |  | 
|  | 6816 | // if wback && (n == 15 || n == t) then UNPREDICTABLE; | 
|  | 6817 | if (wback && ((n == 15) || (n == t))) | 
|  | 6818 | return false; | 
|  | 6819 |  | 
|  | 6820 | break; | 
|  | 6821 |  | 
|  | 6822 | default: | 
|  | 6823 | return false; | 
|  | 6824 | } | 
|  | 6825 |  | 
|  | 6826 | // offset = Shift(R[m], shift_t, shift_n, APSR.C); | 
|  | 6827 |  | 
|  | 6828 | uint64_t Rm  = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + m, 0, &success); | 
|  | 6829 | if (!success) | 
|  | 6830 | return false; | 
|  | 6831 |  | 
| Johnny Chen | a4438a7 | 2011-06-02 22:50:51 +0000 | [diff] [blame] | 6832 | addr_t offset = Shift (Rm, shift_t, shift_n, APSR_C, &success); | 
|  | 6833 | if (!success) | 
|  | 6834 | return false; | 
| Caroline Tice | 0e6bc95 | 2011-03-01 18:00:42 +0000 | [diff] [blame] | 6835 |  | 
|  | 6836 | addr_t offset_addr; | 
|  | 6837 | addr_t address; | 
|  | 6838 |  | 
|  | 6839 | // offset_addr = if add then (R[n] + offset) else (R[n] - offset); | 
|  | 6840 | uint64_t Rn = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success); | 
|  | 6841 | if (!success) | 
|  | 6842 | return false; | 
|  | 6843 |  | 
|  | 6844 | if (add) | 
|  | 6845 | offset_addr = Rn + offset; | 
|  | 6846 | else | 
|  | 6847 | offset_addr = Rn - offset; | 
|  | 6848 |  | 
|  | 6849 | // address = if index then offset_addr else R[n]; | 
|  | 6850 | if (index) | 
|  | 6851 | address = offset_addr; | 
|  | 6852 | else | 
|  | 6853 | address = Rn; | 
|  | 6854 |  | 
|  | 6855 | // data = MemU[address,2]; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 6856 | RegisterInfo base_reg; | 
|  | 6857 | RegisterInfo offset_reg; | 
|  | 6858 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
|  | 6859 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + m, offset_reg); | 
| Caroline Tice | 0e6bc95 | 2011-03-01 18:00:42 +0000 | [diff] [blame] | 6860 |  | 
|  | 6861 | EmulateInstruction::Context context; | 
|  | 6862 | context.type = eContextRegisterLoad; | 
|  | 6863 | context.SetRegisterPlusIndirectOffset (base_reg, offset_reg); | 
|  | 6864 | uint64_t data = MemURead (context, address, 2, 0, &success); | 
|  | 6865 | if (!success) | 
|  | 6866 | return false; | 
|  | 6867 |  | 
|  | 6868 | // if wback then R[n] = offset_addr; | 
|  | 6869 | if (wback) | 
|  | 6870 | { | 
|  | 6871 | context.type = eContextAdjustBaseRegister; | 
|  | 6872 | context.SetAddress (offset_addr); | 
|  | 6873 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr)) | 
|  | 6874 | return false; | 
|  | 6875 | } | 
|  | 6876 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 6877 | // if UnalignedSupport() || address<0> = '0' then | 
| Caroline Tice | 0e6bc95 | 2011-03-01 18:00:42 +0000 | [diff] [blame] | 6878 | if (UnalignedSupport() || BitIsClear (address, 0)) | 
|  | 6879 | { | 
|  | 6880 | // R[t] = ZeroExtend(data, 32); | 
|  | 6881 | context.type = eContextRegisterLoad; | 
|  | 6882 | context.SetRegisterPlusIndirectOffset (base_reg, offset_reg); | 
|  | 6883 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, data)) | 
|  | 6884 | return false; | 
|  | 6885 | } | 
|  | 6886 | else // Can only apply before ARMv7 | 
|  | 6887 | { | 
|  | 6888 | // R[t] = bits(32) UNKNOWN; | 
|  | 6889 | WriteBits32Unknown (t); | 
|  | 6890 | } | 
|  | 6891 | } | 
|  | 6892 | return true; | 
|  | 6893 | } | 
|  | 6894 |  | 
| Caroline Tice | a5e28af | 2011-03-01 21:53:03 +0000 | [diff] [blame] | 6895 | // LDRSB (immediate) calculates an address from a base register value and an immediate offset, loads a byte from | 
|  | 6896 | // memory, sign-extends it to form a 32-bit word, and writes it to a register.  It can use offset, post-indexed, | 
|  | 6897 | // or pre-indexed addressing. | 
|  | 6898 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 6899 | EmulateInstructionARM::EmulateLDRSBImmediate (const uint32_t opcode, const ARMEncoding encoding) | 
| Caroline Tice | a5e28af | 2011-03-01 21:53:03 +0000 | [diff] [blame] | 6900 | { | 
|  | 6901 | #if 0 | 
|  | 6902 | if ConditionPassed() then | 
|  | 6903 | EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | 6904 | offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | 6905 | address = if index then offset_addr else R[n]; | 
|  | 6906 | R[t] = SignExtend(MemU[address,1], 32); | 
|  | 6907 | if wback then R[n] = offset_addr; | 
|  | 6908 | #endif | 
|  | 6909 |  | 
|  | 6910 | bool success = false; | 
| Caroline Tice | a5e28af | 2011-03-01 21:53:03 +0000 | [diff] [blame] | 6911 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 6912 | if (ConditionPassed(opcode)) | 
| Caroline Tice | a5e28af | 2011-03-01 21:53:03 +0000 | [diff] [blame] | 6913 | { | 
|  | 6914 | uint32_t t; | 
|  | 6915 | uint32_t n; | 
|  | 6916 | uint32_t imm32; | 
|  | 6917 | bool index; | 
|  | 6918 | bool add; | 
|  | 6919 | bool wback; | 
|  | 6920 |  | 
|  | 6921 | // EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | 6922 | switch (encoding) | 
|  | 6923 | { | 
|  | 6924 | case eEncodingT1: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 6925 | // if Rt == '1111' then SEE PLI; | 
|  | 6926 | // if Rn == '1111' then SEE LDRSB (literal); | 
| Caroline Tice | a5e28af | 2011-03-01 21:53:03 +0000 | [diff] [blame] | 6927 | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32); | 
|  | 6928 | t = Bits32 (opcode, 15, 12); | 
|  | 6929 | n = Bits32 (opcode, 19, 16); | 
|  | 6930 | imm32 = Bits32 (opcode, 11, 0); | 
|  | 6931 |  | 
|  | 6932 | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | 6933 | index = true; | 
|  | 6934 | add = true; | 
|  | 6935 | wback = false; | 
|  | 6936 |  | 
|  | 6937 | // if t == 13 then UNPREDICTABLE; | 
|  | 6938 | if (t == 13) | 
|  | 6939 | return false; | 
|  | 6940 |  | 
|  | 6941 | break; | 
|  | 6942 |  | 
|  | 6943 | case eEncodingT2: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 6944 | // if Rt == '1111' && P == '1' && U == '0' && W == '0' then SEE PLI; | 
|  | 6945 | // if Rn == '1111' then SEE LDRSB (literal); | 
|  | 6946 | // if P == '1' && U == '1' && W == '0' then SEE LDRSBT; | 
|  | 6947 | // if P == '0' && W == '0' then UNDEFINED; | 
| Caroline Tice | a5e28af | 2011-03-01 21:53:03 +0000 | [diff] [blame] | 6948 | if (BitIsClear (opcode, 10) && BitIsClear (opcode, 8)) | 
|  | 6949 | return false; | 
|  | 6950 |  | 
|  | 6951 | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32); | 
|  | 6952 | t = Bits32 (opcode, 15, 12); | 
|  | 6953 | n = Bits32 (opcode, 19, 16); | 
|  | 6954 | imm32 = Bits32 (opcode, 7, 0); | 
|  | 6955 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 6956 | // index = (P == '1'); add = (U == '1'); wback = (W == '1'); | 
| Caroline Tice | a5e28af | 2011-03-01 21:53:03 +0000 | [diff] [blame] | 6957 | index = BitIsSet (opcode, 10); | 
|  | 6958 | add = BitIsSet (opcode, 9); | 
|  | 6959 | wback = BitIsSet (opcode, 8); | 
|  | 6960 |  | 
|  | 6961 | // if BadReg(t) || (wback && n == t) then UNPREDICTABLE; | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 6962 | if (((t == 13) || ((t == 15) | 
|  | 6963 | && (BitIsClear (opcode, 10) || BitIsSet (opcode, 9) || BitIsSet (opcode, 8)))) | 
|  | 6964 | || (wback && (n == t))) | 
| Caroline Tice | a5e28af | 2011-03-01 21:53:03 +0000 | [diff] [blame] | 6965 | return false; | 
|  | 6966 |  | 
|  | 6967 | break; | 
|  | 6968 |  | 
|  | 6969 | case eEncodingA1: | 
|  | 6970 | { | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 6971 | // if Rn == '1111' then SEE LDRSB (literal); | 
|  | 6972 | // if P == '0' && W == '1' then SEE LDRSBT; | 
| Caroline Tice | a5e28af | 2011-03-01 21:53:03 +0000 | [diff] [blame] | 6973 | // t == UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm4H:imm4L, 32); | 
|  | 6974 | t = Bits32 (opcode, 15, 12); | 
|  | 6975 | n = Bits32 (opcode, 19, 16); | 
|  | 6976 |  | 
|  | 6977 | uint32_t imm4H = Bits32 (opcode, 11, 8); | 
|  | 6978 | uint32_t imm4L = Bits32 (opcode, 3, 0); | 
| Caroline Tice | 40b1a6c | 2011-03-03 00:07:02 +0000 | [diff] [blame] | 6979 | imm32 = (imm4H << 4) | imm4L; | 
| Caroline Tice | a5e28af | 2011-03-01 21:53:03 +0000 | [diff] [blame] | 6980 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 6981 | // index = (P == '1');	add = (U == '1');	wback = (P == '0') || (W == '1'); | 
| Caroline Tice | a5e28af | 2011-03-01 21:53:03 +0000 | [diff] [blame] | 6982 | index = BitIsSet (opcode, 24); | 
|  | 6983 | add = BitIsSet (opcode, 23); | 
|  | 6984 | wback = (BitIsClear (opcode, 24) || BitIsSet (opcode, 21)); | 
|  | 6985 |  | 
|  | 6986 | // if t == 15 || (wback && n == t) then UNPREDICTABLE; | 
|  | 6987 | if ((t == 15) || (wback && (n == t))) | 
|  | 6988 | return false; | 
|  | 6989 |  | 
|  | 6990 | break; | 
|  | 6991 | } | 
|  | 6992 |  | 
|  | 6993 | default: | 
|  | 6994 | return false; | 
|  | 6995 | } | 
|  | 6996 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 6997 | uint64_t Rn = ReadCoreReg (n, &success); | 
| Caroline Tice | a5e28af | 2011-03-01 21:53:03 +0000 | [diff] [blame] | 6998 | if (!success) | 
|  | 6999 | return false; | 
|  | 7000 |  | 
|  | 7001 | addr_t offset_addr; | 
|  | 7002 | addr_t address; | 
|  | 7003 |  | 
|  | 7004 | // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | 7005 | if (add) | 
|  | 7006 | offset_addr = Rn + imm32; | 
|  | 7007 | else | 
|  | 7008 | offset_addr = Rn - imm32; | 
|  | 7009 |  | 
|  | 7010 | // address = if index then offset_addr else R[n]; | 
|  | 7011 | if (index) | 
|  | 7012 | address = offset_addr; | 
|  | 7013 | else | 
|  | 7014 | address = Rn; | 
|  | 7015 |  | 
|  | 7016 | // R[t] = SignExtend(MemU[address,1], 32); | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 7017 | RegisterInfo base_reg; | 
|  | 7018 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
| Caroline Tice | a5e28af | 2011-03-01 21:53:03 +0000 | [diff] [blame] | 7019 |  | 
|  | 7020 | EmulateInstruction::Context context; | 
|  | 7021 | context.type = eContextRegisterLoad; | 
|  | 7022 | context.SetRegisterPlusOffset (base_reg, address - Rn); | 
|  | 7023 |  | 
|  | 7024 | uint64_t unsigned_data = MemURead (context, address, 1, 0, &success); | 
|  | 7025 | if (!success) | 
|  | 7026 | return false; | 
|  | 7027 |  | 
|  | 7028 | int64_t signed_data = llvm::SignExtend64<8>(unsigned_data); | 
|  | 7029 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, (uint64_t) signed_data)) | 
|  | 7030 | return false; | 
|  | 7031 |  | 
|  | 7032 | // if wback then R[n] = offset_addr; | 
|  | 7033 | if (wback) | 
|  | 7034 | { | 
|  | 7035 | context.type = eContextAdjustBaseRegister; | 
|  | 7036 | context.SetAddress (offset_addr); | 
|  | 7037 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr)) | 
|  | 7038 | return false; | 
|  | 7039 | } | 
|  | 7040 | } | 
|  | 7041 |  | 
|  | 7042 | return true; | 
|  | 7043 | } | 
| Caroline Tice | 0e6bc95 | 2011-03-01 18:00:42 +0000 | [diff] [blame] | 7044 |  | 
| Caroline Tice | 5f59391 | 2011-03-01 22:25:17 +0000 | [diff] [blame] | 7045 | // LDRSB (literal) calculates an address from the PC value and an immediate offset, loads a byte from memory, | 
|  | 7046 | // sign-extends it to form a 32-bit word, and writes tit to a register. | 
|  | 7047 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 7048 | EmulateInstructionARM::EmulateLDRSBLiteral (const uint32_t opcode, const ARMEncoding encoding) | 
| Caroline Tice | 5f59391 | 2011-03-01 22:25:17 +0000 | [diff] [blame] | 7049 | { | 
|  | 7050 | #if 0 | 
|  | 7051 | if ConditionPassed() then | 
|  | 7052 | EncodingSpecificOperations(); NullCheckIfThumbEE(15); | 
|  | 7053 | base = Align(PC,4); | 
|  | 7054 | address = if add then (base + imm32) else (base - imm32); | 
|  | 7055 | R[t] = SignExtend(MemU[address,1], 32); | 
|  | 7056 | #endif | 
|  | 7057 |  | 
|  | 7058 | bool success = false; | 
| Caroline Tice | 5f59391 | 2011-03-01 22:25:17 +0000 | [diff] [blame] | 7059 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 7060 | if (ConditionPassed(opcode)) | 
| Caroline Tice | 5f59391 | 2011-03-01 22:25:17 +0000 | [diff] [blame] | 7061 | { | 
|  | 7062 | uint32_t t; | 
|  | 7063 | uint32_t imm32; | 
|  | 7064 | bool add; | 
|  | 7065 |  | 
|  | 7066 | // EncodingSpecificOperations(); NullCheckIfThumbEE(15); | 
|  | 7067 | switch (encoding) | 
|  | 7068 | { | 
|  | 7069 | case eEncodingT1: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 7070 | // if Rt == '1111' then SEE PLI; | 
|  | 7071 | // t = UInt(Rt); imm32 = ZeroExtend(imm12, 32); add = (U == '1'); | 
| Caroline Tice | 5f59391 | 2011-03-01 22:25:17 +0000 | [diff] [blame] | 7072 | t = Bits32 (opcode, 15, 12); | 
|  | 7073 | imm32 = Bits32 (opcode, 11, 0); | 
|  | 7074 | add = BitIsSet (opcode, 23); | 
|  | 7075 |  | 
|  | 7076 | // if t == 13 then UNPREDICTABLE; | 
|  | 7077 | if (t == 13) | 
|  | 7078 | return false; | 
|  | 7079 |  | 
|  | 7080 | break; | 
|  | 7081 |  | 
|  | 7082 | case eEncodingA1: | 
|  | 7083 | { | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 7084 | // t == UInt(Rt); imm32 = ZeroExtend(imm4H:imm4L, 32); add = (U == '1'); | 
| Caroline Tice | 5f59391 | 2011-03-01 22:25:17 +0000 | [diff] [blame] | 7085 | t = Bits32 (opcode, 15, 12); | 
|  | 7086 | uint32_t imm4H = Bits32 (opcode, 11, 8); | 
|  | 7087 | uint32_t imm4L = Bits32 (opcode, 3, 0); | 
| Caroline Tice | 40b1a6c | 2011-03-03 00:07:02 +0000 | [diff] [blame] | 7088 | imm32 = (imm4H << 4) | imm4L; | 
| Caroline Tice | 5f59391 | 2011-03-01 22:25:17 +0000 | [diff] [blame] | 7089 | add = BitIsSet (opcode, 23); | 
|  | 7090 |  | 
|  | 7091 | // if t == 15 then UNPREDICTABLE; | 
|  | 7092 | if (t == 15) | 
|  | 7093 | return false; | 
|  | 7094 |  | 
|  | 7095 | break; | 
|  | 7096 | } | 
|  | 7097 |  | 
|  | 7098 | default: | 
|  | 7099 | return false; | 
|  | 7100 | } | 
|  | 7101 |  | 
|  | 7102 | // base = Align(PC,4); | 
| Caroline Tice | 8d681f5 | 2011-03-17 23:50:16 +0000 | [diff] [blame] | 7103 | uint64_t pc_value = ReadCoreReg (PC_REG, &success); | 
| Caroline Tice | 5f59391 | 2011-03-01 22:25:17 +0000 | [diff] [blame] | 7104 | if (!success) | 
|  | 7105 | return false; | 
|  | 7106 | uint64_t base = AlignPC (pc_value); | 
|  | 7107 |  | 
|  | 7108 | // address = if add then (base + imm32) else (base - imm32); | 
|  | 7109 | addr_t address; | 
|  | 7110 | if (add) | 
|  | 7111 | address = base + imm32; | 
|  | 7112 | else | 
|  | 7113 | address = base - imm32; | 
|  | 7114 |  | 
|  | 7115 | // R[t] = SignExtend(MemU[address,1], 32); | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 7116 | RegisterInfo base_reg; | 
|  | 7117 | GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, base_reg); | 
| Caroline Tice | 5f59391 | 2011-03-01 22:25:17 +0000 | [diff] [blame] | 7118 |  | 
|  | 7119 | EmulateInstruction::Context context; | 
|  | 7120 | context.type = eContextRegisterLoad; | 
|  | 7121 | context.SetRegisterPlusOffset (base_reg, address - base); | 
|  | 7122 |  | 
|  | 7123 | uint64_t unsigned_data = MemURead (context, address, 1, 0, &success); | 
|  | 7124 | if (!success) | 
|  | 7125 | return false; | 
|  | 7126 |  | 
|  | 7127 | int64_t signed_data = llvm::SignExtend64<8>(unsigned_data); | 
|  | 7128 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, (uint64_t) signed_data)) | 
|  | 7129 | return false; | 
|  | 7130 | } | 
|  | 7131 | return true; | 
|  | 7132 | } | 
|  | 7133 |  | 
| Caroline Tice | 672f311 | 2011-03-01 23:55:59 +0000 | [diff] [blame] | 7134 | // LDRSB (register) calculates an address from a base register value and an offset register value, loadsa byte from | 
|  | 7135 | // memory, sign-extends it to form a 32-bit word, and writes it to a register.  The offset register value can be | 
|  | 7136 | // shifted left by 0, 1, 2, or 3 bits. | 
|  | 7137 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 7138 | EmulateInstructionARM::EmulateLDRSBRegister (const uint32_t opcode, const ARMEncoding encoding) | 
| Caroline Tice | 672f311 | 2011-03-01 23:55:59 +0000 | [diff] [blame] | 7139 | { | 
|  | 7140 | #if 0 | 
|  | 7141 | if ConditionPassed() then | 
|  | 7142 | EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | 7143 | offset = Shift(R[m], shift_t, shift_n, APSR.C); | 
|  | 7144 | offset_addr = if add then (R[n] + offset) else (R[n] - offset); | 
|  | 7145 | address = if index then offset_addr else R[n]; | 
|  | 7146 | R[t] = SignExtend(MemU[address,1], 32); | 
|  | 7147 | if wback then R[n] = offset_addr; | 
|  | 7148 | #endif | 
|  | 7149 |  | 
|  | 7150 | bool success = false; | 
| Caroline Tice | 672f311 | 2011-03-01 23:55:59 +0000 | [diff] [blame] | 7151 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 7152 | if (ConditionPassed(opcode)) | 
| Caroline Tice | 672f311 | 2011-03-01 23:55:59 +0000 | [diff] [blame] | 7153 | { | 
|  | 7154 | uint32_t t; | 
|  | 7155 | uint32_t n; | 
|  | 7156 | uint32_t m; | 
|  | 7157 | bool index; | 
|  | 7158 | bool add; | 
|  | 7159 | bool wback; | 
|  | 7160 | ARM_ShifterType shift_t; | 
|  | 7161 | uint32_t shift_n; | 
|  | 7162 |  | 
|  | 7163 | // EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | 7164 | switch (encoding) | 
|  | 7165 | { | 
|  | 7166 | case eEncodingT1: | 
|  | 7167 | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); | 
|  | 7168 | t = Bits32 (opcode, 2, 0); | 
|  | 7169 | n = Bits32 (opcode, 5, 3); | 
|  | 7170 | m = Bits32 (opcode, 8, 6); | 
|  | 7171 |  | 
|  | 7172 | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | 7173 | index = true; | 
|  | 7174 | add = true; | 
|  | 7175 | wback = false; | 
|  | 7176 |  | 
|  | 7177 | // (shift_t, shift_n) = (SRType_LSL, 0); | 
|  | 7178 | shift_t = SRType_LSL; | 
|  | 7179 | shift_n = 0; | 
|  | 7180 |  | 
|  | 7181 | break; | 
|  | 7182 |  | 
|  | 7183 | case eEncodingT2: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 7184 | // if Rt == '1111' then SEE PLI; | 
|  | 7185 | // if Rn == '1111' then SEE LDRSB (literal); | 
| Caroline Tice | 672f311 | 2011-03-01 23:55:59 +0000 | [diff] [blame] | 7186 | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); | 
|  | 7187 | t = Bits32 (opcode, 15, 12); | 
|  | 7188 | n = Bits32 (opcode, 19, 16); | 
|  | 7189 | m = Bits32 (opcode, 3, 0); | 
|  | 7190 |  | 
|  | 7191 | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | 7192 | index = true; | 
|  | 7193 | add = true; | 
|  | 7194 | wback = false; | 
|  | 7195 |  | 
|  | 7196 | // (shift_t, shift_n) = (SRType_LSL, UInt(imm2)); | 
|  | 7197 | shift_t = SRType_LSL; | 
|  | 7198 | shift_n = Bits32 (opcode, 5, 4); | 
|  | 7199 |  | 
|  | 7200 | // if t == 13 || BadReg(m) then UNPREDICTABLE; | 
|  | 7201 | if ((t == 13) || BadReg (m)) | 
|  | 7202 | return false; | 
|  | 7203 | break; | 
|  | 7204 |  | 
|  | 7205 | case eEncodingA1: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 7206 | // if P == '0' && W == '1' then SEE LDRSBT; | 
| Caroline Tice | 672f311 | 2011-03-01 23:55:59 +0000 | [diff] [blame] | 7207 | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); | 
|  | 7208 | t = Bits32 (opcode, 15, 12); | 
|  | 7209 | n = Bits32 (opcode, 19, 16); | 
|  | 7210 | m = Bits32 (opcode, 3, 0); | 
|  | 7211 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 7212 | // index = (P == '1');	add = (U == '1');	wback = (P == '0') || (W == '1'); | 
| Caroline Tice | 672f311 | 2011-03-01 23:55:59 +0000 | [diff] [blame] | 7213 | index = BitIsSet (opcode, 24); | 
|  | 7214 | add = BitIsSet (opcode, 23); | 
|  | 7215 | wback = BitIsClear (opcode, 24) || BitIsSet (opcode, 21); | 
|  | 7216 |  | 
|  | 7217 | // (shift_t, shift_n) = (SRType_LSL, 0); | 
|  | 7218 | shift_t = SRType_LSL; | 
|  | 7219 | shift_n = 0; | 
|  | 7220 |  | 
|  | 7221 | // if t == 15 || m == 15 then UNPREDICTABLE; | 
|  | 7222 | if ((t == 15) || (m == 15)) | 
|  | 7223 | return false; | 
|  | 7224 |  | 
|  | 7225 | // if wback && (n == 15 || n == t) then UNPREDICTABLE; | 
|  | 7226 | if (wback && ((n == 15) || (n == t))) | 
|  | 7227 | return false; | 
|  | 7228 | break; | 
|  | 7229 |  | 
|  | 7230 | default: | 
|  | 7231 | return false; | 
|  | 7232 | } | 
|  | 7233 |  | 
|  | 7234 | uint64_t Rm =  ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + m, 0, &success); | 
|  | 7235 | if (!success) | 
|  | 7236 | return false; | 
|  | 7237 |  | 
|  | 7238 | // offset = Shift(R[m], shift_t, shift_n, APSR.C); | 
| Johnny Chen | a4438a7 | 2011-06-02 22:50:51 +0000 | [diff] [blame] | 7239 | addr_t offset = Shift (Rm, shift_t, shift_n, APSR_C, &success); | 
|  | 7240 | if (!success) | 
|  | 7241 | return false; | 
| Caroline Tice | 672f311 | 2011-03-01 23:55:59 +0000 | [diff] [blame] | 7242 |  | 
|  | 7243 | addr_t offset_addr; | 
|  | 7244 | addr_t address; | 
|  | 7245 |  | 
|  | 7246 | // offset_addr = if add then (R[n] + offset) else (R[n] - offset); | 
|  | 7247 | uint64_t Rn = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success); | 
|  | 7248 | if (!success) | 
|  | 7249 | return false; | 
|  | 7250 |  | 
|  | 7251 | if (add) | 
|  | 7252 | offset_addr = Rn + offset; | 
|  | 7253 | else | 
|  | 7254 | offset_addr = Rn - offset; | 
|  | 7255 |  | 
|  | 7256 | // address = if index then offset_addr else R[n]; | 
|  | 7257 | if (index) | 
|  | 7258 | address = offset_addr; | 
|  | 7259 | else | 
|  | 7260 | address = Rn; | 
|  | 7261 |  | 
|  | 7262 | // R[t] = SignExtend(MemU[address,1], 32); | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 7263 | RegisterInfo base_reg; | 
|  | 7264 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
|  | 7265 | RegisterInfo offset_reg; | 
|  | 7266 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + m, offset_reg); | 
| Caroline Tice | 672f311 | 2011-03-01 23:55:59 +0000 | [diff] [blame] | 7267 |  | 
|  | 7268 | EmulateInstruction::Context context; | 
|  | 7269 | context.type = eContextRegisterLoad; | 
|  | 7270 | context.SetRegisterPlusIndirectOffset (base_reg, offset_reg); | 
|  | 7271 |  | 
|  | 7272 | uint64_t unsigned_data = MemURead (context, address, 1, 0, &success); | 
|  | 7273 | if (!success) | 
|  | 7274 | return false; | 
|  | 7275 |  | 
|  | 7276 | int64_t signed_data = llvm::SignExtend64<8>(unsigned_data); | 
|  | 7277 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, (uint64_t) signed_data)) | 
|  | 7278 | return false; | 
|  | 7279 |  | 
|  | 7280 | // if wback then R[n] = offset_addr; | 
|  | 7281 | if (wback) | 
|  | 7282 | { | 
|  | 7283 | context.type = eContextAdjustBaseRegister; | 
|  | 7284 | context.SetAddress (offset_addr); | 
|  | 7285 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr)) | 
|  | 7286 | return false; | 
|  | 7287 | } | 
|  | 7288 | } | 
|  | 7289 | return true; | 
|  | 7290 | } | 
|  | 7291 |  | 
| Caroline Tice | 78fb563 | 2011-03-02 00:39:42 +0000 | [diff] [blame] | 7292 | // LDRSH (immediate) calculates an address from a base register value and an immediate offset, loads a halfword from | 
|  | 7293 | // memory, sign-extends it to form a 32-bit word, and writes it to a register.  It can use offset, post-indexed, or | 
|  | 7294 | // pre-indexed addressing. | 
|  | 7295 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 7296 | EmulateInstructionARM::EmulateLDRSHImmediate (const uint32_t opcode, const ARMEncoding encoding) | 
| Caroline Tice | 78fb563 | 2011-03-02 00:39:42 +0000 | [diff] [blame] | 7297 | { | 
|  | 7298 | #if 0 | 
|  | 7299 | if ConditionPassed() then | 
|  | 7300 | EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | 7301 | offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | 7302 | address = if index then offset_addr else R[n]; | 
|  | 7303 | data = MemU[address,2]; | 
|  | 7304 | if wback then R[n] = offset_addr; | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 7305 | if UnalignedSupport() || address<0> = '0' then | 
| Caroline Tice | 78fb563 | 2011-03-02 00:39:42 +0000 | [diff] [blame] | 7306 | R[t] = SignExtend(data, 32); | 
|  | 7307 | else // Can only apply before ARMv7 | 
|  | 7308 | R[t] = bits(32) UNKNOWN; | 
|  | 7309 | #endif | 
|  | 7310 |  | 
|  | 7311 | bool success = false; | 
| Caroline Tice | 78fb563 | 2011-03-02 00:39:42 +0000 | [diff] [blame] | 7312 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 7313 | if (ConditionPassed(opcode)) | 
| Caroline Tice | 78fb563 | 2011-03-02 00:39:42 +0000 | [diff] [blame] | 7314 | { | 
|  | 7315 | uint32_t t; | 
|  | 7316 | uint32_t n; | 
|  | 7317 | uint32_t imm32; | 
|  | 7318 | bool index; | 
|  | 7319 | bool add; | 
|  | 7320 | bool wback; | 
|  | 7321 |  | 
|  | 7322 | // EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | 7323 | switch (encoding) | 
|  | 7324 | { | 
|  | 7325 | case eEncodingT1: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 7326 | // if Rn == '1111' then SEE LDRSH (literal); | 
|  | 7327 | // if Rt == '1111' then SEE "Unallocated memory hints"; | 
| Caroline Tice | 78fb563 | 2011-03-02 00:39:42 +0000 | [diff] [blame] | 7328 | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32); | 
|  | 7329 | t = Bits32 (opcode, 15, 12); | 
|  | 7330 | n = Bits32 (opcode, 19, 16); | 
|  | 7331 | imm32 = Bits32 (opcode, 11, 0); | 
|  | 7332 |  | 
|  | 7333 | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | 7334 | index = true; | 
|  | 7335 | add = true; | 
|  | 7336 | wback = false; | 
|  | 7337 |  | 
|  | 7338 | // if t == 13 then UNPREDICTABLE; | 
|  | 7339 | if (t == 13) | 
|  | 7340 | return false; | 
|  | 7341 |  | 
|  | 7342 | break; | 
|  | 7343 |  | 
|  | 7344 | case eEncodingT2: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 7345 | // if Rn == '1111' then SEE LDRSH (literal); | 
|  | 7346 | // if Rt == '1111' && P == '1' && U == '0' && W == '0' then SEE "Unallocated memory hints"; | 
|  | 7347 | // if P == '1' && U == '1' && W == '0' then SEE LDRSHT; | 
|  | 7348 | // if P == '0' && W == '0' then UNDEFINED; | 
| Caroline Tice | 78fb563 | 2011-03-02 00:39:42 +0000 | [diff] [blame] | 7349 | if (BitIsClear (opcode, 10) && BitIsClear (opcode, 8)) | 
|  | 7350 | return false; | 
|  | 7351 |  | 
|  | 7352 | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32); | 
|  | 7353 | t = Bits32 (opcode, 15, 12); | 
|  | 7354 | n = Bits32 (opcode, 19, 16); | 
|  | 7355 | imm32 = Bits32 (opcode, 7, 0); | 
|  | 7356 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 7357 | // index = (P == '1'); add = (U == '1'); wback = (W == '1'); | 
| Caroline Tice | 78fb563 | 2011-03-02 00:39:42 +0000 | [diff] [blame] | 7358 | index = BitIsSet (opcode, 10); | 
|  | 7359 | add = BitIsSet (opcode, 9); | 
|  | 7360 | wback = BitIsSet (opcode, 8); | 
|  | 7361 |  | 
|  | 7362 | // if BadReg(t) || (wback && n == t) then UNPREDICTABLE; | 
|  | 7363 | if (BadReg (t) || (wback && (n == t))) | 
|  | 7364 | return false; | 
|  | 7365 |  | 
|  | 7366 | break; | 
|  | 7367 |  | 
|  | 7368 | case eEncodingA1: | 
|  | 7369 | { | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 7370 | // if Rn == '1111' then SEE LDRSH (literal); | 
|  | 7371 | // if P == '0' && W == '1' then SEE LDRSHT; | 
| Caroline Tice | 78fb563 | 2011-03-02 00:39:42 +0000 | [diff] [blame] | 7372 | // t == UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm4H:imm4L, 32); | 
|  | 7373 | t = Bits32 (opcode, 15, 12); | 
|  | 7374 | n = Bits32 (opcode, 19, 16); | 
|  | 7375 | uint32_t imm4H = Bits32 (opcode, 11,8); | 
|  | 7376 | uint32_t imm4L = Bits32 (opcode, 3, 0); | 
| Caroline Tice | 40b1a6c | 2011-03-03 00:07:02 +0000 | [diff] [blame] | 7377 | imm32 = (imm4H << 4) | imm4L; | 
| Caroline Tice | 78fb563 | 2011-03-02 00:39:42 +0000 | [diff] [blame] | 7378 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 7379 | // index = (P == '1');	add = (U == '1');	wback = (P == '0') || (W == '1'); | 
| Caroline Tice | 78fb563 | 2011-03-02 00:39:42 +0000 | [diff] [blame] | 7380 | index = BitIsSet (opcode, 24); | 
|  | 7381 | add = BitIsSet (opcode, 23); | 
|  | 7382 | wback = BitIsClear (opcode, 24) || BitIsSet (opcode, 21); | 
|  | 7383 |  | 
|  | 7384 | // if t == 15 || (wback && n == t) then UNPREDICTABLE; | 
|  | 7385 | if ((t == 15) || (wback && (n == t))) | 
|  | 7386 | return false; | 
|  | 7387 |  | 
|  | 7388 | break; | 
|  | 7389 | } | 
|  | 7390 |  | 
|  | 7391 | default: | 
|  | 7392 | return false; | 
|  | 7393 | } | 
|  | 7394 |  | 
|  | 7395 | // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | 7396 | uint64_t Rn = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success); | 
|  | 7397 | if (!success) | 
|  | 7398 | return false; | 
|  | 7399 |  | 
|  | 7400 | addr_t offset_addr; | 
|  | 7401 | if (add) | 
|  | 7402 | offset_addr = Rn + imm32; | 
|  | 7403 | else | 
|  | 7404 | offset_addr = Rn - imm32; | 
|  | 7405 |  | 
|  | 7406 | // address = if index then offset_addr else R[n]; | 
|  | 7407 | addr_t address; | 
|  | 7408 | if (index) | 
|  | 7409 | address = offset_addr; | 
|  | 7410 | else | 
|  | 7411 | address = Rn; | 
|  | 7412 |  | 
|  | 7413 | // data = MemU[address,2]; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 7414 | RegisterInfo base_reg; | 
|  | 7415 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
| Caroline Tice | 78fb563 | 2011-03-02 00:39:42 +0000 | [diff] [blame] | 7416 |  | 
|  | 7417 | EmulateInstruction::Context context; | 
|  | 7418 | context.type = eContextRegisterLoad; | 
|  | 7419 | context.SetRegisterPlusOffset (base_reg, address - Rn); | 
|  | 7420 |  | 
|  | 7421 | uint64_t data = MemURead (context, address, 2, 0, &success); | 
|  | 7422 | if (!success) | 
|  | 7423 | return false; | 
|  | 7424 |  | 
|  | 7425 | // if wback then R[n] = offset_addr; | 
|  | 7426 | if (wback) | 
|  | 7427 | { | 
|  | 7428 | context.type = eContextAdjustBaseRegister; | 
|  | 7429 | context.SetAddress (offset_addr); | 
|  | 7430 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr)) | 
|  | 7431 | return false; | 
|  | 7432 | } | 
|  | 7433 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 7434 | // if UnalignedSupport() || address<0> = '0' then | 
| Caroline Tice | 78fb563 | 2011-03-02 00:39:42 +0000 | [diff] [blame] | 7435 | if (UnalignedSupport() || BitIsClear (address, 0)) | 
|  | 7436 | { | 
|  | 7437 | // R[t] = SignExtend(data, 32); | 
|  | 7438 | int64_t signed_data = llvm::SignExtend64<16>(data); | 
|  | 7439 | context.type = eContextRegisterLoad; | 
|  | 7440 | context.SetRegisterPlusOffset (base_reg, address - Rn); | 
|  | 7441 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, (uint64_t) signed_data)) | 
|  | 7442 | return false; | 
|  | 7443 | } | 
|  | 7444 | else // Can only apply before ARMv7 | 
|  | 7445 | { | 
|  | 7446 | // R[t] = bits(32) UNKNOWN; | 
|  | 7447 | WriteBits32Unknown (t); | 
|  | 7448 | } | 
|  | 7449 | } | 
|  | 7450 | return true; | 
|  | 7451 | } | 
|  | 7452 |  | 
| Caroline Tice | d2fac09 | 2011-03-02 19:45:34 +0000 | [diff] [blame] | 7453 | // LDRSH (literal) calculates an address from the PC value and an immediate offset, loads a halfword from memory, | 
|  | 7454 | // sign-extends it to from a 32-bit word, and writes it to a register. | 
|  | 7455 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 7456 | EmulateInstructionARM::EmulateLDRSHLiteral (const uint32_t opcode, const ARMEncoding encoding) | 
| Caroline Tice | d2fac09 | 2011-03-02 19:45:34 +0000 | [diff] [blame] | 7457 | { | 
|  | 7458 | #if 0 | 
|  | 7459 | if ConditionPassed() then | 
|  | 7460 | EncodingSpecificOperations(); NullCheckIfThumbEE(15); | 
|  | 7461 | base = Align(PC,4); | 
|  | 7462 | address = if add then (base + imm32) else (base - imm32); | 
|  | 7463 | data = MemU[address,2]; | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 7464 | if UnalignedSupport() || address<0> = '0' then | 
| Caroline Tice | d2fac09 | 2011-03-02 19:45:34 +0000 | [diff] [blame] | 7465 | R[t] = SignExtend(data, 32); | 
|  | 7466 | else // Can only apply before ARMv7 | 
|  | 7467 | R[t] = bits(32) UNKNOWN; | 
|  | 7468 | #endif | 
|  | 7469 |  | 
|  | 7470 | bool success = false; | 
| Caroline Tice | d2fac09 | 2011-03-02 19:45:34 +0000 | [diff] [blame] | 7471 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 7472 | if (ConditionPassed(opcode)) | 
| Caroline Tice | d2fac09 | 2011-03-02 19:45:34 +0000 | [diff] [blame] | 7473 | { | 
|  | 7474 | uint32_t t; | 
|  | 7475 | uint32_t imm32; | 
|  | 7476 | bool add; | 
|  | 7477 |  | 
|  | 7478 | // EncodingSpecificOperations(); NullCheckIfThumbEE(15); | 
|  | 7479 | switch (encoding) | 
|  | 7480 | { | 
|  | 7481 | case eEncodingT1: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 7482 | // if Rt == '1111' then SEE "Unallocated memory hints"; | 
|  | 7483 | // t = UInt(Rt); imm32 = ZeroExtend(imm12, 32); add = (U == '1'); | 
| Caroline Tice | d2fac09 | 2011-03-02 19:45:34 +0000 | [diff] [blame] | 7484 | t = Bits32  (opcode, 15, 12); | 
|  | 7485 | imm32 = Bits32 (opcode, 11, 0); | 
|  | 7486 | add = BitIsSet (opcode, 23); | 
|  | 7487 |  | 
|  | 7488 | // if t == 13 then UNPREDICTABLE; | 
|  | 7489 | if (t == 13) | 
|  | 7490 | return false; | 
|  | 7491 |  | 
|  | 7492 | break; | 
|  | 7493 |  | 
|  | 7494 | case eEncodingA1: | 
|  | 7495 | { | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 7496 | // t == UInt(Rt); imm32 = ZeroExtend(imm4H:imm4L, 32); add = (U == '1'); | 
| Caroline Tice | d2fac09 | 2011-03-02 19:45:34 +0000 | [diff] [blame] | 7497 | t = Bits32 (opcode, 15, 12); | 
|  | 7498 | uint32_t imm4H = Bits32 (opcode, 11, 8); | 
|  | 7499 | uint32_t imm4L = Bits32 (opcode, 3, 0); | 
| Caroline Tice | 40b1a6c | 2011-03-03 00:07:02 +0000 | [diff] [blame] | 7500 | imm32 = (imm4H << 4) | imm4L; | 
| Caroline Tice | d2fac09 | 2011-03-02 19:45:34 +0000 | [diff] [blame] | 7501 | add = BitIsSet (opcode, 23); | 
|  | 7502 |  | 
|  | 7503 | // if t == 15 then UNPREDICTABLE; | 
|  | 7504 | if (t == 15) | 
|  | 7505 | return false; | 
|  | 7506 |  | 
|  | 7507 | break; | 
|  | 7508 | } | 
|  | 7509 | default: | 
|  | 7510 | return false; | 
|  | 7511 | } | 
|  | 7512 |  | 
|  | 7513 | // base = Align(PC,4); | 
| Caroline Tice | 8d681f5 | 2011-03-17 23:50:16 +0000 | [diff] [blame] | 7514 | uint64_t pc_value = ReadCoreReg (PC_REG, &success); | 
| Caroline Tice | d2fac09 | 2011-03-02 19:45:34 +0000 | [diff] [blame] | 7515 | if (!success) | 
|  | 7516 | return false; | 
|  | 7517 |  | 
|  | 7518 | uint64_t base = AlignPC (pc_value); | 
|  | 7519 |  | 
|  | 7520 | addr_t address; | 
|  | 7521 | // address = if add then (base + imm32) else (base - imm32); | 
|  | 7522 | if (add) | 
|  | 7523 | address = base + imm32; | 
|  | 7524 | else | 
|  | 7525 | address = base - imm32; | 
|  | 7526 |  | 
|  | 7527 | // data = MemU[address,2]; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 7528 | RegisterInfo base_reg; | 
|  | 7529 | GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, base_reg); | 
| Caroline Tice | d2fac09 | 2011-03-02 19:45:34 +0000 | [diff] [blame] | 7530 |  | 
|  | 7531 | EmulateInstruction::Context context; | 
|  | 7532 | context.type = eContextRegisterLoad; | 
|  | 7533 | context.SetRegisterPlusOffset (base_reg, imm32); | 
|  | 7534 |  | 
|  | 7535 | uint64_t data = MemURead (context, address, 2, 0, &success); | 
|  | 7536 | if (!success) | 
|  | 7537 | return false; | 
|  | 7538 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 7539 | // if UnalignedSupport() || address<0> = '0' then | 
| Caroline Tice | d2fac09 | 2011-03-02 19:45:34 +0000 | [diff] [blame] | 7540 | if (UnalignedSupport() || BitIsClear (address, 0)) | 
|  | 7541 | { | 
|  | 7542 | // R[t] = SignExtend(data, 32); | 
|  | 7543 | int64_t signed_data = llvm::SignExtend64<16>(data); | 
|  | 7544 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, (uint64_t) signed_data)) | 
|  | 7545 | return false; | 
|  | 7546 | } | 
|  | 7547 | else // Can only apply before ARMv7 | 
|  | 7548 | { | 
|  | 7549 | // R[t] = bits(32) UNKNOWN; | 
|  | 7550 | WriteBits32Unknown (t); | 
|  | 7551 | } | 
|  | 7552 | } | 
|  | 7553 | return true; | 
|  | 7554 | } | 
|  | 7555 |  | 
| Caroline Tice | 291a3e9 | 2011-03-02 21:13:44 +0000 | [diff] [blame] | 7556 | // LDRSH (register) calculates an address from a base register value and an offset register value, loads a halfword | 
|  | 7557 | // from memory, sign-extends it to form a 32-bit word, and writes it to a register.  The offset register value can be | 
|  | 7558 | // shifted left by 0, 1, 2, or 3 bits. | 
|  | 7559 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 7560 | EmulateInstructionARM::EmulateLDRSHRegister (const uint32_t opcode, const ARMEncoding encoding) | 
| Caroline Tice | 291a3e9 | 2011-03-02 21:13:44 +0000 | [diff] [blame] | 7561 | { | 
|  | 7562 | #if 0 | 
|  | 7563 | if ConditionPassed() then | 
|  | 7564 | EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | 7565 | offset = Shift(R[m], shift_t, shift_n, APSR.C); | 
|  | 7566 | offset_addr = if add then (R[n] + offset) else (R[n] - offset); | 
|  | 7567 | address = if index then offset_addr else R[n]; | 
|  | 7568 | data = MemU[address,2]; | 
|  | 7569 | if wback then R[n] = offset_addr; | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 7570 | if UnalignedSupport() || address<0> = '0' then | 
| Caroline Tice | 291a3e9 | 2011-03-02 21:13:44 +0000 | [diff] [blame] | 7571 | R[t] = SignExtend(data, 32); | 
|  | 7572 | else // Can only apply before ARMv7 | 
|  | 7573 | R[t] = bits(32) UNKNOWN; | 
|  | 7574 | #endif | 
|  | 7575 |  | 
|  | 7576 | bool success = false; | 
| Caroline Tice | 291a3e9 | 2011-03-02 21:13:44 +0000 | [diff] [blame] | 7577 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 7578 | if (ConditionPassed(opcode)) | 
| Caroline Tice | 291a3e9 | 2011-03-02 21:13:44 +0000 | [diff] [blame] | 7579 | { | 
|  | 7580 | uint32_t t; | 
|  | 7581 | uint32_t n; | 
|  | 7582 | uint32_t m; | 
|  | 7583 | bool index; | 
|  | 7584 | bool add; | 
|  | 7585 | bool wback; | 
|  | 7586 | ARM_ShifterType shift_t; | 
|  | 7587 | uint32_t shift_n; | 
|  | 7588 |  | 
|  | 7589 | // EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | 7590 | switch (encoding) | 
|  | 7591 | { | 
|  | 7592 | case eEncodingT1: | 
|  | 7593 | // if CurrentInstrSet() == InstrSet_ThumbEE then SEE "Modified operation in ThumbEE"; | 
|  | 7594 | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); | 
|  | 7595 | t = Bits32 (opcode, 2, 0); | 
|  | 7596 | n = Bits32 (opcode, 5, 3); | 
|  | 7597 | m = Bits32 (opcode, 8, 6); | 
|  | 7598 |  | 
|  | 7599 | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | 7600 | index = true; | 
|  | 7601 | add = true; | 
|  | 7602 | wback = false; | 
|  | 7603 |  | 
|  | 7604 | // (shift_t, shift_n) = (SRType_LSL, 0); | 
|  | 7605 | shift_t = SRType_LSL; | 
|  | 7606 | shift_n = 0; | 
|  | 7607 |  | 
|  | 7608 | break; | 
|  | 7609 |  | 
|  | 7610 | case eEncodingT2: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 7611 | // if Rn == '1111' then SEE LDRSH (literal); | 
|  | 7612 | // if Rt == '1111' then SEE "Unallocated memory hints"; | 
| Caroline Tice | 291a3e9 | 2011-03-02 21:13:44 +0000 | [diff] [blame] | 7613 | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); | 
|  | 7614 | t = Bits32 (opcode, 15, 12); | 
|  | 7615 | n = Bits32 (opcode, 19, 16); | 
|  | 7616 | m = Bits32 (opcode, 3, 0); | 
|  | 7617 |  | 
|  | 7618 | // index = TRUE; add = TRUE; wback = FALSE; | 
|  | 7619 | index = true; | 
|  | 7620 | add = true; | 
|  | 7621 | wback = false; | 
|  | 7622 |  | 
|  | 7623 | // (shift_t, shift_n) = (SRType_LSL, UInt(imm2)); | 
|  | 7624 | shift_t = SRType_LSL; | 
|  | 7625 | shift_n = Bits32 (opcode, 5, 4); | 
|  | 7626 |  | 
|  | 7627 | // if t == 13 || BadReg(m) then UNPREDICTABLE; | 
|  | 7628 | if ((t == 13) || BadReg (m)) | 
|  | 7629 | return false; | 
|  | 7630 |  | 
|  | 7631 | break; | 
|  | 7632 |  | 
|  | 7633 | case eEncodingA1: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 7634 | // if P == '0' && W == '1' then SEE LDRSHT; | 
| Caroline Tice | 291a3e9 | 2011-03-02 21:13:44 +0000 | [diff] [blame] | 7635 | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); | 
|  | 7636 | t = Bits32 (opcode, 15, 12); | 
|  | 7637 | n = Bits32 (opcode, 19, 16); | 
|  | 7638 | m = Bits32 (opcode, 3, 0); | 
|  | 7639 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 7640 | // index = (P == '1');	add = (U == '1');	wback = (P == '0') || (W == '1'); | 
| Caroline Tice | 291a3e9 | 2011-03-02 21:13:44 +0000 | [diff] [blame] | 7641 | index = BitIsSet (opcode, 24); | 
|  | 7642 | add = BitIsSet (opcode, 23); | 
|  | 7643 | wback = BitIsClear (opcode, 24) || BitIsSet (opcode, 21); | 
|  | 7644 |  | 
|  | 7645 | // (shift_t, shift_n) = (SRType_LSL, 0); | 
|  | 7646 | shift_t = SRType_LSL; | 
|  | 7647 | shift_n = 0; | 
|  | 7648 |  | 
|  | 7649 | // if t == 15 || m == 15 then UNPREDICTABLE; | 
|  | 7650 | if ((t == 15) || (m == 15)) | 
|  | 7651 | return false; | 
|  | 7652 |  | 
|  | 7653 | // if wback && (n == 15 || n == t) then UNPREDICTABLE; | 
|  | 7654 | if (wback && ((n == 15) || (n == t))) | 
|  | 7655 | return false; | 
|  | 7656 |  | 
|  | 7657 | break; | 
|  | 7658 |  | 
|  | 7659 | default: | 
| Johnny Chen | 6ac9e54 | 2011-08-16 01:16:02 +0000 | [diff] [blame^] | 7660 | return false; | 
| Caroline Tice | 291a3e9 | 2011-03-02 21:13:44 +0000 | [diff] [blame] | 7661 | } | 
|  | 7662 |  | 
|  | 7663 | uint64_t Rm = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + m, 0, &success); | 
|  | 7664 | if (!success) | 
|  | 7665 | return false; | 
|  | 7666 |  | 
|  | 7667 | uint64_t Rn = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success); | 
|  | 7668 | if (!success) | 
|  | 7669 | return false; | 
|  | 7670 |  | 
|  | 7671 | // offset = Shift(R[m], shift_t, shift_n, APSR.C); | 
| Johnny Chen | a4438a7 | 2011-06-02 22:50:51 +0000 | [diff] [blame] | 7672 | addr_t offset = Shift (Rm, shift_t, shift_n, APSR_C, &success); | 
|  | 7673 | if (!success) | 
|  | 7674 | return false; | 
| Caroline Tice | 291a3e9 | 2011-03-02 21:13:44 +0000 | [diff] [blame] | 7675 |  | 
|  | 7676 | addr_t offset_addr; | 
|  | 7677 | addr_t address; | 
|  | 7678 |  | 
|  | 7679 | // offset_addr = if add then (R[n] + offset) else (R[n] - offset); | 
|  | 7680 | if (add) | 
|  | 7681 | offset_addr = Rn + offset; | 
|  | 7682 | else | 
|  | 7683 | offset_addr = Rn - offset; | 
|  | 7684 |  | 
|  | 7685 | // address = if index then offset_addr else R[n]; | 
|  | 7686 | if (index) | 
|  | 7687 | address = offset_addr; | 
|  | 7688 | else | 
|  | 7689 | address = Rn; | 
|  | 7690 |  | 
|  | 7691 | // data = MemU[address,2]; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 7692 | RegisterInfo base_reg; | 
|  | 7693 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
| Caroline Tice | 291a3e9 | 2011-03-02 21:13:44 +0000 | [diff] [blame] | 7694 |  | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 7695 | RegisterInfo offset_reg; | 
|  | 7696 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + m, offset_reg); | 
| Caroline Tice | 291a3e9 | 2011-03-02 21:13:44 +0000 | [diff] [blame] | 7697 |  | 
|  | 7698 | EmulateInstruction::Context context; | 
|  | 7699 | context.type = eContextRegisterLoad; | 
|  | 7700 | context.SetRegisterPlusIndirectOffset (base_reg, offset_reg); | 
|  | 7701 |  | 
|  | 7702 | uint64_t data = MemURead (context, address, 2, 0, &success); | 
|  | 7703 | if (!success) | 
|  | 7704 | return false; | 
|  | 7705 |  | 
|  | 7706 | // if wback then R[n] = offset_addr; | 
|  | 7707 | if (wback) | 
|  | 7708 | { | 
|  | 7709 | context.type = eContextAdjustBaseRegister; | 
|  | 7710 | context.SetAddress (offset_addr); | 
|  | 7711 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr)) | 
|  | 7712 | return false; | 
|  | 7713 | } | 
|  | 7714 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 7715 | // if UnalignedSupport() || address<0> = '0' then | 
| Caroline Tice | 291a3e9 | 2011-03-02 21:13:44 +0000 | [diff] [blame] | 7716 | if (UnalignedSupport() || BitIsClear (address, 0)) | 
|  | 7717 | { | 
|  | 7718 | // R[t] = SignExtend(data, 32); | 
|  | 7719 | context.type = eContextRegisterLoad; | 
|  | 7720 | context.SetRegisterPlusIndirectOffset (base_reg, offset_reg); | 
|  | 7721 |  | 
|  | 7722 | int64_t signed_data = llvm::SignExtend64<16>(data); | 
|  | 7723 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, (uint64_t) signed_data)) | 
|  | 7724 | return false; | 
|  | 7725 | } | 
|  | 7726 | else // Can only apply before ARMv7 | 
|  | 7727 | { | 
|  | 7728 | // R[t] = bits(32) UNKNOWN; | 
|  | 7729 | WriteBits32Unknown (t); | 
|  | 7730 | } | 
|  | 7731 | } | 
|  | 7732 | return true; | 
|  | 7733 | } | 
| Caroline Tice | 6bf6516 | 2011-03-03 17:42:58 +0000 | [diff] [blame] | 7734 |  | 
|  | 7735 | // SXTB extracts an 8-bit value from a register, sign-extends it to 32 bits, and writes the result to the destination | 
|  | 7736 | // register.  You can specifiy a rotation by 0, 8, 16, or 24 bits before extracting the 8-bit value. | 
|  | 7737 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 7738 | EmulateInstructionARM::EmulateSXTB (const uint32_t opcode, const ARMEncoding encoding) | 
| Caroline Tice | 6bf6516 | 2011-03-03 17:42:58 +0000 | [diff] [blame] | 7739 | { | 
|  | 7740 | #if 0 | 
|  | 7741 | if ConditionPassed() then | 
|  | 7742 | EncodingSpecificOperations(); | 
|  | 7743 | rotated = ROR(R[m], rotation); | 
|  | 7744 | R[d] = SignExtend(rotated<7:0>, 32); | 
|  | 7745 | #endif | 
|  | 7746 |  | 
|  | 7747 | bool success = false; | 
| Caroline Tice | 6bf6516 | 2011-03-03 17:42:58 +0000 | [diff] [blame] | 7748 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 7749 | if (ConditionPassed(opcode)) | 
| Caroline Tice | 6bf6516 | 2011-03-03 17:42:58 +0000 | [diff] [blame] | 7750 | { | 
|  | 7751 | uint32_t d; | 
|  | 7752 | uint32_t m; | 
|  | 7753 | uint32_t rotation; | 
|  | 7754 |  | 
|  | 7755 | // EncodingSpecificOperations(); | 
|  | 7756 | switch (encoding) | 
|  | 7757 | { | 
|  | 7758 | case eEncodingT1: | 
|  | 7759 | // d = UInt(Rd); m = UInt(Rm); rotation = 0; | 
|  | 7760 | d = Bits32 (opcode, 2, 0); | 
|  | 7761 | m = Bits32 (opcode, 5, 3); | 
|  | 7762 | rotation = 0; | 
|  | 7763 |  | 
|  | 7764 | break; | 
|  | 7765 |  | 
|  | 7766 | case eEncodingT2: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 7767 | // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000'); | 
| Caroline Tice | 6bf6516 | 2011-03-03 17:42:58 +0000 | [diff] [blame] | 7768 | d = Bits32 (opcode, 11, 8); | 
|  | 7769 | m = Bits32 (opcode, 3, 0); | 
|  | 7770 | rotation = Bits32 (opcode, 5, 4) << 3; | 
|  | 7771 |  | 
|  | 7772 | // if BadReg(d) || BadReg(m) then UNPREDICTABLE; | 
|  | 7773 | if (BadReg (d) || BadReg (m)) | 
|  | 7774 | return false; | 
|  | 7775 |  | 
|  | 7776 | break; | 
|  | 7777 |  | 
|  | 7778 | case eEncodingA1: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 7779 | // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000'); | 
| Caroline Tice | 6bf6516 | 2011-03-03 17:42:58 +0000 | [diff] [blame] | 7780 | d = Bits32 (opcode, 15, 12); | 
|  | 7781 | m = Bits32 (opcode, 3, 0); | 
|  | 7782 | rotation = Bits32 (opcode, 11, 10) << 3; | 
|  | 7783 |  | 
|  | 7784 | // if d == 15 || m == 15 then UNPREDICTABLE; | 
|  | 7785 | if ((d == 15) || (m == 15)) | 
|  | 7786 | return false; | 
|  | 7787 |  | 
|  | 7788 | break; | 
|  | 7789 |  | 
|  | 7790 | default: | 
|  | 7791 | return false; | 
|  | 7792 | } | 
|  | 7793 |  | 
| Caroline Tice | 868198b | 2011-03-03 18:04:49 +0000 | [diff] [blame] | 7794 | uint64_t Rm = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + m, 0, &success); | 
|  | 7795 | if (!success) | 
|  | 7796 | return false; | 
| Caroline Tice | 6bf6516 | 2011-03-03 17:42:58 +0000 | [diff] [blame] | 7797 |  | 
|  | 7798 | // rotated = ROR(R[m], rotation); | 
| Johnny Chen | a4438a7 | 2011-06-02 22:50:51 +0000 | [diff] [blame] | 7799 | uint64_t rotated = ROR (Rm, rotation, &success); | 
|  | 7800 | if (!success) | 
|  | 7801 | return false; | 
| Caroline Tice | 6bf6516 | 2011-03-03 17:42:58 +0000 | [diff] [blame] | 7802 |  | 
|  | 7803 | // R[d] = SignExtend(rotated<7:0>, 32); | 
| Caroline Tice | 8ce96d9 | 2011-03-03 18:27:17 +0000 | [diff] [blame] | 7804 | int64_t data = llvm::SignExtend64<8>(rotated); | 
| Caroline Tice | 6bf6516 | 2011-03-03 17:42:58 +0000 | [diff] [blame] | 7805 |  | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 7806 | RegisterInfo source_reg; | 
|  | 7807 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + m, source_reg); | 
| Caroline Tice | 6bf6516 | 2011-03-03 17:42:58 +0000 | [diff] [blame] | 7808 |  | 
|  | 7809 | EmulateInstruction::Context context; | 
|  | 7810 | context.type = eContextRegisterLoad; | 
|  | 7811 | context.SetRegister (source_reg); | 
|  | 7812 |  | 
| Caroline Tice | 8ce96d9 | 2011-03-03 18:27:17 +0000 | [diff] [blame] | 7813 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + d, (uint64_t) data)) | 
| Caroline Tice | 6bf6516 | 2011-03-03 17:42:58 +0000 | [diff] [blame] | 7814 | return false; | 
|  | 7815 | } | 
|  | 7816 | return true; | 
|  | 7817 | } | 
| Caroline Tice | 291a3e9 | 2011-03-02 21:13:44 +0000 | [diff] [blame] | 7818 |  | 
| Caroline Tice | 868198b | 2011-03-03 18:04:49 +0000 | [diff] [blame] | 7819 | // SXTH extracts a 16-bit value from a register, sign-extends it to 32 bits, and writes the result to the destination | 
|  | 7820 | // register.  You can specify a rotation by 0, 8, 16, or 24 bits before extracting the 16-bit value. | 
|  | 7821 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 7822 | EmulateInstructionARM::EmulateSXTH (const uint32_t opcode, const ARMEncoding encoding) | 
| Caroline Tice | 868198b | 2011-03-03 18:04:49 +0000 | [diff] [blame] | 7823 | { | 
|  | 7824 | #if 0 | 
|  | 7825 | if ConditionPassed() then | 
|  | 7826 | EncodingSpecificOperations(); | 
|  | 7827 | rotated = ROR(R[m], rotation); | 
|  | 7828 | R[d] = SignExtend(rotated<15:0>, 32); | 
|  | 7829 | #endif | 
|  | 7830 |  | 
|  | 7831 | bool success = false; | 
| Caroline Tice | 868198b | 2011-03-03 18:04:49 +0000 | [diff] [blame] | 7832 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 7833 | if (ConditionPassed(opcode)) | 
| Caroline Tice | 868198b | 2011-03-03 18:04:49 +0000 | [diff] [blame] | 7834 | { | 
|  | 7835 | uint32_t d; | 
|  | 7836 | uint32_t m; | 
|  | 7837 | uint32_t rotation; | 
|  | 7838 |  | 
|  | 7839 | // EncodingSpecificOperations(); | 
|  | 7840 | switch (encoding) | 
|  | 7841 | { | 
|  | 7842 | case eEncodingT1: | 
|  | 7843 | // d = UInt(Rd); m = UInt(Rm); rotation = 0; | 
|  | 7844 | d = Bits32 (opcode, 2, 0); | 
|  | 7845 | m = Bits32 (opcode, 5, 3); | 
|  | 7846 | rotation = 0; | 
|  | 7847 |  | 
|  | 7848 | break; | 
|  | 7849 |  | 
|  | 7850 | case eEncodingT2: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 7851 | // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000'); | 
| Caroline Tice | 868198b | 2011-03-03 18:04:49 +0000 | [diff] [blame] | 7852 | d = Bits32 (opcode, 11, 8); | 
|  | 7853 | m = Bits32 (opcode, 3, 0); | 
|  | 7854 | rotation = Bits32 (opcode, 5, 4) << 3; | 
|  | 7855 |  | 
|  | 7856 | // if BadReg(d) || BadReg(m) then UNPREDICTABLE; | 
|  | 7857 | if (BadReg (d) || BadReg (m)) | 
|  | 7858 | return false; | 
|  | 7859 |  | 
|  | 7860 | break; | 
|  | 7861 |  | 
|  | 7862 | case eEncodingA1: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 7863 | // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000'); | 
| Caroline Tice | 868198b | 2011-03-03 18:04:49 +0000 | [diff] [blame] | 7864 | d = Bits32 (opcode, 15, 12); | 
|  | 7865 | m = Bits32 (opcode, 3, 0); | 
|  | 7866 | rotation = Bits32 (opcode, 11, 10) << 3; | 
|  | 7867 |  | 
|  | 7868 | // if d == 15 || m == 15 then UNPREDICTABLE; | 
|  | 7869 | if ((d == 15) || (m == 15)) | 
|  | 7870 | return false; | 
|  | 7871 |  | 
|  | 7872 | break; | 
|  | 7873 |  | 
|  | 7874 | default: | 
|  | 7875 | return false; | 
|  | 7876 | } | 
|  | 7877 |  | 
|  | 7878 | uint64_t Rm = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + m, 0, &success); | 
|  | 7879 | if (!success) | 
|  | 7880 | return false; | 
|  | 7881 |  | 
|  | 7882 | // rotated = ROR(R[m], rotation); | 
| Johnny Chen | a4438a7 | 2011-06-02 22:50:51 +0000 | [diff] [blame] | 7883 | uint64_t rotated = ROR (Rm, rotation, &success); | 
|  | 7884 | if (!success) | 
|  | 7885 | return false; | 
| Caroline Tice | 868198b | 2011-03-03 18:04:49 +0000 | [diff] [blame] | 7886 |  | 
|  | 7887 | // R[d] = SignExtend(rotated<15:0>, 32); | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 7888 | RegisterInfo source_reg; | 
|  | 7889 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + m, source_reg); | 
| Caroline Tice | 868198b | 2011-03-03 18:04:49 +0000 | [diff] [blame] | 7890 |  | 
|  | 7891 | EmulateInstruction::Context context; | 
|  | 7892 | context.type = eContextRegisterLoad; | 
|  | 7893 | context.SetRegister (source_reg); | 
|  | 7894 |  | 
| Caroline Tice | 8ce96d9 | 2011-03-03 18:27:17 +0000 | [diff] [blame] | 7895 | int64_t data = llvm::SignExtend64<16> (rotated); | 
|  | 7896 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + d, (uint64_t) data)) | 
| Caroline Tice | 868198b | 2011-03-03 18:04:49 +0000 | [diff] [blame] | 7897 | return false; | 
|  | 7898 | } | 
|  | 7899 |  | 
|  | 7900 | return true; | 
|  | 7901 | } | 
|  | 7902 |  | 
| Caroline Tice | 8ce96d9 | 2011-03-03 18:27:17 +0000 | [diff] [blame] | 7903 | // UXTB extracts an 8-bit value from a register, zero-extneds it to 32 bits, and writes the result to the destination | 
|  | 7904 | // register.  You can specify a rotation by 0, 8, 16, or 24 bits before extracting the 8-bit value. | 
|  | 7905 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 7906 | EmulateInstructionARM::EmulateUXTB (const uint32_t opcode, const ARMEncoding encoding) | 
| Caroline Tice | 8ce96d9 | 2011-03-03 18:27:17 +0000 | [diff] [blame] | 7907 | { | 
|  | 7908 | #if 0 | 
|  | 7909 | if ConditionPassed() then | 
|  | 7910 | EncodingSpecificOperations(); | 
|  | 7911 | rotated = ROR(R[m], rotation); | 
|  | 7912 | R[d] = ZeroExtend(rotated<7:0>, 32); | 
|  | 7913 | #endif | 
|  | 7914 |  | 
|  | 7915 | bool success = false; | 
| Caroline Tice | 8ce96d9 | 2011-03-03 18:27:17 +0000 | [diff] [blame] | 7916 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 7917 | if (ConditionPassed(opcode)) | 
| Caroline Tice | 8ce96d9 | 2011-03-03 18:27:17 +0000 | [diff] [blame] | 7918 | { | 
|  | 7919 | uint32_t d; | 
|  | 7920 | uint32_t m; | 
|  | 7921 | uint32_t rotation; | 
|  | 7922 |  | 
|  | 7923 | // EncodingSpecificOperations(); | 
|  | 7924 | switch (encoding) | 
|  | 7925 | { | 
|  | 7926 | case eEncodingT1: | 
|  | 7927 | // d = UInt(Rd); m = UInt(Rm); rotation = 0; | 
|  | 7928 | d = Bits32 (opcode, 2, 0); | 
|  | 7929 | m = Bits32 (opcode, 5, 3); | 
|  | 7930 | rotation = 0; | 
|  | 7931 |  | 
|  | 7932 | break; | 
|  | 7933 |  | 
|  | 7934 | case eEncodingT2: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 7935 | // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000'); | 
| Caroline Tice | 8ce96d9 | 2011-03-03 18:27:17 +0000 | [diff] [blame] | 7936 | d = Bits32 (opcode, 11, 8); | 
|  | 7937 | m = Bits32 (opcode, 3, 0); | 
|  | 7938 | rotation = Bits32 (opcode, 5, 4) << 3; | 
|  | 7939 |  | 
|  | 7940 | // if BadReg(d) || BadReg(m) then UNPREDICTABLE; | 
|  | 7941 | if (BadReg (d) || BadReg (m)) | 
|  | 7942 | return false; | 
|  | 7943 |  | 
|  | 7944 | break; | 
|  | 7945 |  | 
|  | 7946 | case eEncodingA1: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 7947 | // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000'); | 
| Caroline Tice | 8ce96d9 | 2011-03-03 18:27:17 +0000 | [diff] [blame] | 7948 | d = Bits32 (opcode, 15, 12); | 
|  | 7949 | m = Bits32 (opcode, 3, 0); | 
|  | 7950 | rotation = Bits32 (opcode, 11, 10) << 3; | 
|  | 7951 |  | 
|  | 7952 | // if d == 15 || m == 15 then UNPREDICTABLE; | 
|  | 7953 | if ((d == 15) || (m == 15)) | 
|  | 7954 | return false; | 
|  | 7955 |  | 
|  | 7956 | break; | 
|  | 7957 |  | 
|  | 7958 | default: | 
|  | 7959 | return false; | 
|  | 7960 | } | 
|  | 7961 |  | 
|  | 7962 | uint64_t Rm = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + m, 0, &success); | 
|  | 7963 | if (!success) | 
|  | 7964 | return false; | 
|  | 7965 |  | 
|  | 7966 | // rotated = ROR(R[m], rotation); | 
| Johnny Chen | a4438a7 | 2011-06-02 22:50:51 +0000 | [diff] [blame] | 7967 | uint64_t rotated = ROR (Rm, rotation, &success); | 
|  | 7968 | if (!success) | 
|  | 7969 | return false; | 
| Caroline Tice | 8ce96d9 | 2011-03-03 18:27:17 +0000 | [diff] [blame] | 7970 |  | 
|  | 7971 | // R[d] = ZeroExtend(rotated<7:0>, 32); | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 7972 | RegisterInfo source_reg; | 
|  | 7973 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + m, source_reg); | 
| Caroline Tice | 8ce96d9 | 2011-03-03 18:27:17 +0000 | [diff] [blame] | 7974 |  | 
|  | 7975 | EmulateInstruction::Context context; | 
|  | 7976 | context.type = eContextRegisterLoad; | 
|  | 7977 | context.SetRegister (source_reg); | 
|  | 7978 |  | 
|  | 7979 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + d, Bits32 (rotated, 7, 0))) | 
|  | 7980 | return false; | 
|  | 7981 | } | 
|  | 7982 | return true; | 
|  | 7983 | } | 
|  | 7984 |  | 
| Caroline Tice | 11555f2 | 2011-03-03 18:48:58 +0000 | [diff] [blame] | 7985 | // UXTH extracts a 16-bit value from a register, zero-extends it to 32 bits, and writes the result to the destination | 
|  | 7986 | // register.  You can specify a rotation by 0, 8, 16, or 24 bits before extracting the 16-bit value. | 
|  | 7987 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 7988 | EmulateInstructionARM::EmulateUXTH (const uint32_t opcode, const ARMEncoding encoding) | 
| Caroline Tice | 11555f2 | 2011-03-03 18:48:58 +0000 | [diff] [blame] | 7989 | { | 
|  | 7990 | #if 0 | 
|  | 7991 | if ConditionPassed() then | 
|  | 7992 | EncodingSpecificOperations(); | 
|  | 7993 | rotated = ROR(R[m], rotation); | 
|  | 7994 | R[d] = ZeroExtend(rotated<15:0>, 32); | 
|  | 7995 | #endif | 
|  | 7996 |  | 
|  | 7997 | bool success = false; | 
| Caroline Tice | 11555f2 | 2011-03-03 18:48:58 +0000 | [diff] [blame] | 7998 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 7999 | if (ConditionPassed(opcode)) | 
| Caroline Tice | 11555f2 | 2011-03-03 18:48:58 +0000 | [diff] [blame] | 8000 | { | 
|  | 8001 | uint32_t d; | 
|  | 8002 | uint32_t m; | 
|  | 8003 | uint32_t rotation; | 
|  | 8004 |  | 
|  | 8005 | switch (encoding) | 
|  | 8006 | { | 
|  | 8007 | case eEncodingT1: | 
|  | 8008 | // d = UInt(Rd); m = UInt(Rm); rotation = 0; | 
|  | 8009 | d = Bits32 (opcode, 2, 0); | 
|  | 8010 | m = Bits32 (opcode, 5, 3); | 
|  | 8011 | rotation = 0; | 
|  | 8012 |  | 
|  | 8013 | break; | 
|  | 8014 |  | 
|  | 8015 | case eEncodingT2: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 8016 | // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000'); | 
| Caroline Tice | 11555f2 | 2011-03-03 18:48:58 +0000 | [diff] [blame] | 8017 | d = Bits32 (opcode, 11, 8); | 
|  | 8018 | m = Bits32 (opcode, 3, 0); | 
|  | 8019 | rotation = Bits32 (opcode, 5, 4) << 3; | 
|  | 8020 |  | 
|  | 8021 | // if BadReg(d) || BadReg(m) then UNPREDICTABLE; | 
|  | 8022 | if (BadReg (d) || BadReg (m)) | 
|  | 8023 | return false; | 
|  | 8024 |  | 
|  | 8025 | break; | 
|  | 8026 |  | 
|  | 8027 | case eEncodingA1: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 8028 | // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000'); | 
| Caroline Tice | 11555f2 | 2011-03-03 18:48:58 +0000 | [diff] [blame] | 8029 | d = Bits32 (opcode, 15, 12); | 
|  | 8030 | m = Bits32 (opcode, 3, 0); | 
|  | 8031 | rotation = Bits32 (opcode, 11, 10) << 3; | 
|  | 8032 |  | 
|  | 8033 | // if d == 15 || m == 15 then UNPREDICTABLE; | 
|  | 8034 | if ((d == 15) || (m == 15)) | 
|  | 8035 | return false; | 
|  | 8036 |  | 
|  | 8037 | break; | 
|  | 8038 |  | 
|  | 8039 | default: | 
|  | 8040 | return false; | 
|  | 8041 | } | 
|  | 8042 |  | 
|  | 8043 | uint64_t Rm = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + m, 0, &success); | 
|  | 8044 | if (!success) | 
|  | 8045 | return false; | 
|  | 8046 |  | 
|  | 8047 | // rotated = ROR(R[m], rotation); | 
| Johnny Chen | a4438a7 | 2011-06-02 22:50:51 +0000 | [diff] [blame] | 8048 | uint64_t rotated = ROR (Rm, rotation, &success); | 
|  | 8049 | if (!success) | 
|  | 8050 | return false; | 
| Caroline Tice | 11555f2 | 2011-03-03 18:48:58 +0000 | [diff] [blame] | 8051 |  | 
|  | 8052 | // R[d] = ZeroExtend(rotated<15:0>, 32); | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 8053 | RegisterInfo source_reg; | 
|  | 8054 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + m, source_reg); | 
| Caroline Tice | 11555f2 | 2011-03-03 18:48:58 +0000 | [diff] [blame] | 8055 |  | 
|  | 8056 | EmulateInstruction::Context context; | 
|  | 8057 | context.type = eContextRegisterLoad; | 
|  | 8058 | context.SetRegister (source_reg); | 
|  | 8059 |  | 
|  | 8060 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + d, Bits32 (rotated, 15, 0))) | 
|  | 8061 | return false; | 
|  | 8062 | } | 
|  | 8063 | return true; | 
|  | 8064 | } | 
| Caroline Tice | b27771d | 2011-03-03 22:37:46 +0000 | [diff] [blame] | 8065 |  | 
|  | 8066 | // RFE (Return From Exception) loads the PC and the CPSR from the word at the specified address and the following | 
|  | 8067 | // word respectively. | 
|  | 8068 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 8069 | EmulateInstructionARM::EmulateRFE (const uint32_t opcode, const ARMEncoding encoding) | 
| Caroline Tice | b27771d | 2011-03-03 22:37:46 +0000 | [diff] [blame] | 8070 | { | 
|  | 8071 | #if 0 | 
|  | 8072 | if ConditionPassed() then | 
|  | 8073 | EncodingSpecificOperations(); | 
|  | 8074 | if !CurrentModeIsPrivileged() || CurrentInstrSet() == InstrSet_ThumbEE then | 
|  | 8075 | UNPREDICTABLE; | 
|  | 8076 | else | 
|  | 8077 | address = if increment then R[n] else R[n]-8; | 
|  | 8078 | if wordhigher then address = address+4; | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 8079 | CPSRWriteByInstr(MemA[address+4,4], '1111', TRUE); | 
| Caroline Tice | b27771d | 2011-03-03 22:37:46 +0000 | [diff] [blame] | 8080 | BranchWritePC(MemA[address,4]); | 
|  | 8081 | if wback then R[n] = if increment then R[n]+8 else R[n]-8; | 
|  | 8082 | #endif | 
|  | 8083 |  | 
|  | 8084 | bool success = false; | 
| Caroline Tice | b27771d | 2011-03-03 22:37:46 +0000 | [diff] [blame] | 8085 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 8086 | if (ConditionPassed(opcode)) | 
| Caroline Tice | b27771d | 2011-03-03 22:37:46 +0000 | [diff] [blame] | 8087 | { | 
|  | 8088 | uint32_t n; | 
|  | 8089 | bool wback; | 
|  | 8090 | bool increment; | 
|  | 8091 | bool wordhigher; | 
|  | 8092 |  | 
|  | 8093 | // EncodingSpecificOperations(); | 
|  | 8094 | switch (encoding) | 
|  | 8095 | { | 
|  | 8096 | case eEncodingT1: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 8097 | // n = UInt(Rn); wback = (W == '1'); increment = FALSE; wordhigher = FALSE; | 
| Caroline Tice | b27771d | 2011-03-03 22:37:46 +0000 | [diff] [blame] | 8098 | n = Bits32 (opcode, 19, 16); | 
|  | 8099 | wback = BitIsSet (opcode, 21); | 
|  | 8100 | increment = false; | 
|  | 8101 | wordhigher = false; | 
|  | 8102 |  | 
|  | 8103 | // if n == 15 then UNPREDICTABLE; | 
|  | 8104 | if (n == 15) | 
|  | 8105 | return false; | 
|  | 8106 |  | 
|  | 8107 | // if InITBlock() && !LastInITBlock() then UNPREDICTABLE; | 
|  | 8108 | if (InITBlock() && !LastInITBlock()) | 
|  | 8109 | return false; | 
|  | 8110 |  | 
|  | 8111 | break; | 
|  | 8112 |  | 
|  | 8113 | case eEncodingT2: | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 8114 | // n = UInt(Rn); wback = (W == '1'); increment = TRUE; wordhigher = FALSE; | 
| Caroline Tice | b27771d | 2011-03-03 22:37:46 +0000 | [diff] [blame] | 8115 | n = Bits32 (opcode, 19, 16); | 
|  | 8116 | wback = BitIsSet (opcode, 21); | 
|  | 8117 | increment = true; | 
|  | 8118 | wordhigher = false; | 
|  | 8119 |  | 
|  | 8120 | // if n == 15 then UNPREDICTABLE; | 
|  | 8121 | if (n == 15) | 
|  | 8122 | return false; | 
|  | 8123 |  | 
|  | 8124 | // if InITBlock() && !LastInITBlock() then UNPREDICTABLE; | 
|  | 8125 | if (InITBlock() && !LastInITBlock()) | 
|  | 8126 | return false; | 
|  | 8127 |  | 
|  | 8128 | break; | 
|  | 8129 |  | 
|  | 8130 | case eEncodingA1: | 
|  | 8131 | // n = UInt(Rn); | 
|  | 8132 | n = Bits32 (opcode, 19, 16); | 
|  | 8133 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 8134 | // wback = (W == '1'); inc = (U == '1'); wordhigher = (P == U); | 
| Caroline Tice | b27771d | 2011-03-03 22:37:46 +0000 | [diff] [blame] | 8135 | wback = BitIsSet (opcode, 21); | 
|  | 8136 | increment = BitIsSet (opcode, 23); | 
|  | 8137 | wordhigher = (Bit32 (opcode, 24) == Bit32 (opcode, 23)); | 
|  | 8138 |  | 
|  | 8139 | // if n == 15 then UNPREDICTABLE; | 
|  | 8140 | if (n == 15) | 
|  | 8141 | return false; | 
|  | 8142 |  | 
|  | 8143 | break; | 
|  | 8144 |  | 
|  | 8145 | default: | 
|  | 8146 | return false; | 
|  | 8147 | } | 
|  | 8148 |  | 
|  | 8149 | // if !CurrentModeIsPrivileged() || CurrentInstrSet() == InstrSet_ThumbEE then | 
|  | 8150 | if (!CurrentModeIsPrivileged ()) | 
|  | 8151 | // UNPREDICTABLE; | 
|  | 8152 | return false; | 
|  | 8153 | else | 
|  | 8154 | { | 
|  | 8155 | uint64_t Rn = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success); | 
|  | 8156 | if (!success) | 
|  | 8157 | return false; | 
|  | 8158 |  | 
|  | 8159 | addr_t address; | 
|  | 8160 | // address = if increment then R[n] else R[n]-8; | 
|  | 8161 | if (increment) | 
|  | 8162 | address = Rn; | 
|  | 8163 | else | 
|  | 8164 | address = Rn - 8; | 
|  | 8165 |  | 
|  | 8166 | // if wordhigher then address = address+4; | 
|  | 8167 | if (wordhigher) | 
|  | 8168 | address = address + 4; | 
|  | 8169 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 8170 | // CPSRWriteByInstr(MemA[address+4,4], '1111', TRUE); | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 8171 | RegisterInfo base_reg; | 
|  | 8172 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
| Caroline Tice | b27771d | 2011-03-03 22:37:46 +0000 | [diff] [blame] | 8173 |  | 
|  | 8174 | EmulateInstruction::Context context; | 
|  | 8175 | context.type = eContextReturnFromException; | 
|  | 8176 | context.SetRegisterPlusOffset (base_reg, address - Rn); | 
|  | 8177 |  | 
|  | 8178 | uint64_t data = MemARead (context, address + 4, 4, 0, &success); | 
|  | 8179 | if (!success) | 
|  | 8180 | return false; | 
|  | 8181 |  | 
|  | 8182 | CPSRWriteByInstr (data, 15, true); | 
|  | 8183 |  | 
|  | 8184 | // BranchWritePC(MemA[address,4]); | 
|  | 8185 | uint64_t data2 = MemARead (context, address, 4, 0, &success); | 
|  | 8186 | if (!success) | 
|  | 8187 | return false; | 
|  | 8188 |  | 
|  | 8189 | BranchWritePC (context, data2); | 
|  | 8190 |  | 
|  | 8191 | // if wback then R[n] = if increment then R[n]+8 else R[n]-8; | 
|  | 8192 | if (wback) | 
|  | 8193 | { | 
|  | 8194 | context.type = eContextAdjustBaseRegister; | 
|  | 8195 | if (increment) | 
|  | 8196 | { | 
|  | 8197 | context.SetOffset (8); | 
|  | 8198 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, Rn + 8)) | 
|  | 8199 | return false; | 
|  | 8200 | } | 
|  | 8201 | else | 
|  | 8202 | { | 
|  | 8203 | context.SetOffset (-8); | 
|  | 8204 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, Rn - 8)) | 
|  | 8205 | return false; | 
|  | 8206 | } | 
|  | 8207 | } // if wback | 
|  | 8208 | } | 
|  | 8209 | } // if ConditionPassed() | 
|  | 8210 | return true; | 
|  | 8211 | } | 
| Caroline Tice | 11555f2 | 2011-03-03 18:48:58 +0000 | [diff] [blame] | 8212 |  | 
| Johnny Chen | 2115b41 | 2011-02-21 23:42:44 +0000 | [diff] [blame] | 8213 | // Bitwise Exclusive OR (immediate) performs a bitwise exclusive OR of a register value and an immediate value, | 
|  | 8214 | // and writes the result to the destination register.  It can optionally update the condition flags based on | 
|  | 8215 | // the result. | 
|  | 8216 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 8217 | EmulateInstructionARM::EmulateEORImm (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | 2115b41 | 2011-02-21 23:42:44 +0000 | [diff] [blame] | 8218 | { | 
|  | 8219 | #if 0 | 
|  | 8220 | // ARM pseudo code... | 
|  | 8221 | if ConditionPassed() then | 
|  | 8222 | EncodingSpecificOperations(); | 
|  | 8223 | result = R[n] EOR imm32; | 
|  | 8224 | if d == 15 then         // Can only occur for ARM encoding | 
|  | 8225 | ALUWritePC(result); // setflags is always FALSE here | 
|  | 8226 | else | 
|  | 8227 | R[d] = result; | 
|  | 8228 | if setflags then | 
|  | 8229 | APSR.N = result<31>; | 
|  | 8230 | APSR.Z = IsZeroBit(result); | 
|  | 8231 | APSR.C = carry; | 
|  | 8232 | // APSR.V unchanged | 
|  | 8233 | #endif | 
|  | 8234 |  | 
|  | 8235 | bool success = false; | 
| Johnny Chen | 2115b41 | 2011-02-21 23:42:44 +0000 | [diff] [blame] | 8236 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 8237 | if (ConditionPassed(opcode)) | 
| Johnny Chen | 2115b41 | 2011-02-21 23:42:44 +0000 | [diff] [blame] | 8238 | { | 
|  | 8239 | uint32_t Rd, Rn; | 
|  | 8240 | uint32_t imm32; // the immediate value to be ORed to the value obtained from Rn | 
|  | 8241 | bool setflags; | 
|  | 8242 | uint32_t carry; // the carry bit after ARM/Thumb Expand operation | 
|  | 8243 | switch (encoding) | 
|  | 8244 | { | 
|  | 8245 | case eEncodingT1: | 
|  | 8246 | Rd = Bits32(opcode, 11, 8); | 
|  | 8247 | Rn = Bits32(opcode, 19, 16); | 
|  | 8248 | setflags = BitIsSet(opcode, 20); | 
|  | 8249 | imm32 = ThumbExpandImm_C(opcode, APSR_C, carry); // (imm32, carry) = ThumbExpandImm(i:imm3:imm8, APSR.C) | 
|  | 8250 | // if Rd == '1111' && S == '1' then SEE TEQ (immediate); | 
|  | 8251 | if (Rd == 15 && setflags) | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 8252 | return EmulateTEQImm (opcode, eEncodingT1); | 
| Johnny Chen | 2115b41 | 2011-02-21 23:42:44 +0000 | [diff] [blame] | 8253 | if (Rd == 13 || (Rd == 15 && !setflags) || BadReg(Rn)) | 
|  | 8254 | return false; | 
|  | 8255 | break; | 
|  | 8256 | case eEncodingA1: | 
|  | 8257 | Rd = Bits32(opcode, 15, 12); | 
|  | 8258 | Rn = Bits32(opcode, 19, 16); | 
|  | 8259 | setflags = BitIsSet(opcode, 20); | 
|  | 8260 | imm32 = ARMExpandImm_C(opcode, APSR_C, carry); // (imm32, carry) = ARMExpandImm(imm12, APSR.C) | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 8261 |  | 
| Johnny Chen | 2115b41 | 2011-02-21 23:42:44 +0000 | [diff] [blame] | 8262 | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related instructions; | 
| Johnny Chen | 2115b41 | 2011-02-21 23:42:44 +0000 | [diff] [blame] | 8263 | if (Rd == 15 && setflags) | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 8264 | return EmulateSUBSPcLrEtc (opcode, encoding); | 
| Johnny Chen | 2115b41 | 2011-02-21 23:42:44 +0000 | [diff] [blame] | 8265 | break; | 
|  | 8266 | default: | 
|  | 8267 | return false; | 
|  | 8268 | } | 
|  | 8269 |  | 
|  | 8270 | // Read the first operand. | 
|  | 8271 | uint32_t val1 = ReadCoreReg(Rn, &success); | 
|  | 8272 | if (!success) | 
|  | 8273 | return false; | 
|  | 8274 |  | 
|  | 8275 | uint32_t result = val1 ^ imm32; | 
|  | 8276 |  | 
|  | 8277 | EmulateInstruction::Context context; | 
|  | 8278 | context.type = EmulateInstruction::eContextImmediate; | 
|  | 8279 | context.SetNoArgs (); | 
|  | 8280 |  | 
|  | 8281 | if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry)) | 
|  | 8282 | return false; | 
|  | 8283 | } | 
|  | 8284 | return true; | 
|  | 8285 | } | 
|  | 8286 |  | 
|  | 8287 | // Bitwise Exclusive OR (register) performs a bitwise exclusive OR of a register value and an | 
|  | 8288 | // optionally-shifted register value, and writes the result to the destination register. | 
|  | 8289 | // It can optionally update the condition flags based on the result. | 
|  | 8290 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 8291 | EmulateInstructionARM::EmulateEORReg (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | 2115b41 | 2011-02-21 23:42:44 +0000 | [diff] [blame] | 8292 | { | 
|  | 8293 | #if 0 | 
|  | 8294 | // ARM pseudo code... | 
|  | 8295 | if ConditionPassed() then | 
|  | 8296 | EncodingSpecificOperations(); | 
|  | 8297 | (shifted, carry) = Shift_C(R[m], shift_t, shift_n, APSR.C); | 
|  | 8298 | result = R[n] EOR shifted; | 
|  | 8299 | if d == 15 then         // Can only occur for ARM encoding | 
|  | 8300 | ALUWritePC(result); // setflags is always FALSE here | 
|  | 8301 | else | 
|  | 8302 | R[d] = result; | 
|  | 8303 | if setflags then | 
|  | 8304 | APSR.N = result<31>; | 
|  | 8305 | APSR.Z = IsZeroBit(result); | 
|  | 8306 | APSR.C = carry; | 
|  | 8307 | // APSR.V unchanged | 
|  | 8308 | #endif | 
|  | 8309 |  | 
|  | 8310 | bool success = false; | 
| Johnny Chen | 2115b41 | 2011-02-21 23:42:44 +0000 | [diff] [blame] | 8311 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 8312 | if (ConditionPassed(opcode)) | 
| Johnny Chen | 2115b41 | 2011-02-21 23:42:44 +0000 | [diff] [blame] | 8313 | { | 
|  | 8314 | uint32_t Rd, Rn, Rm; | 
|  | 8315 | ARM_ShifterType shift_t; | 
|  | 8316 | uint32_t shift_n; // the shift applied to the value read from Rm | 
|  | 8317 | bool setflags; | 
|  | 8318 | uint32_t carry; | 
|  | 8319 | switch (encoding) | 
|  | 8320 | { | 
|  | 8321 | case eEncodingT1: | 
|  | 8322 | Rd = Rn = Bits32(opcode, 2, 0); | 
|  | 8323 | Rm = Bits32(opcode, 5, 3); | 
|  | 8324 | setflags = !InITBlock(); | 
|  | 8325 | shift_t = SRType_LSL; | 
|  | 8326 | shift_n = 0; | 
| Johnny Chen | ed32e7c | 2011-02-22 23:42:58 +0000 | [diff] [blame] | 8327 | break; | 
| Johnny Chen | 2115b41 | 2011-02-21 23:42:44 +0000 | [diff] [blame] | 8328 | case eEncodingT2: | 
|  | 8329 | Rd = Bits32(opcode, 11, 8); | 
|  | 8330 | Rn = Bits32(opcode, 19, 16); | 
|  | 8331 | Rm = Bits32(opcode, 3, 0); | 
|  | 8332 | setflags = BitIsSet(opcode, 20); | 
| Johnny Chen | 3dd0605 | 2011-02-22 21:17:52 +0000 | [diff] [blame] | 8333 | shift_n = DecodeImmShiftThumb(opcode, shift_t); | 
|  | 8334 | // if Rd == '1111' && S == '1' then SEE TEQ (register); | 
| Johnny Chen | 2115b41 | 2011-02-21 23:42:44 +0000 | [diff] [blame] | 8335 | if (Rd == 15 && setflags) | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 8336 | return EmulateTEQReg (opcode, eEncodingT1); | 
| Johnny Chen | 2115b41 | 2011-02-21 23:42:44 +0000 | [diff] [blame] | 8337 | if (Rd == 13 || (Rd == 15 && !setflags) || BadReg(Rn) || BadReg(Rm)) | 
|  | 8338 | return false; | 
|  | 8339 | break; | 
|  | 8340 | case eEncodingA1: | 
|  | 8341 | Rd = Bits32(opcode, 15, 12); | 
|  | 8342 | Rn = Bits32(opcode, 19, 16); | 
|  | 8343 | Rm = Bits32(opcode, 3, 0); | 
|  | 8344 | setflags = BitIsSet(opcode, 20); | 
| Johnny Chen | 3dd0605 | 2011-02-22 21:17:52 +0000 | [diff] [blame] | 8345 | shift_n = DecodeImmShiftARM(opcode, shift_t); | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 8346 |  | 
| Johnny Chen | 2115b41 | 2011-02-21 23:42:44 +0000 | [diff] [blame] | 8347 | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related instructions; | 
| Johnny Chen | 2115b41 | 2011-02-21 23:42:44 +0000 | [diff] [blame] | 8348 | if (Rd == 15 && setflags) | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 8349 | return EmulateSUBSPcLrEtc (opcode, encoding); | 
| Johnny Chen | 2115b41 | 2011-02-21 23:42:44 +0000 | [diff] [blame] | 8350 | break; | 
|  | 8351 | default: | 
|  | 8352 | return false; | 
|  | 8353 | } | 
|  | 8354 |  | 
|  | 8355 | // Read the first operand. | 
|  | 8356 | uint32_t val1 = ReadCoreReg(Rn, &success); | 
|  | 8357 | if (!success) | 
|  | 8358 | return false; | 
|  | 8359 |  | 
|  | 8360 | // Read the second operand. | 
|  | 8361 | uint32_t val2 = ReadCoreReg(Rm, &success); | 
|  | 8362 | if (!success) | 
|  | 8363 | return false; | 
|  | 8364 |  | 
| Johnny Chen | a4438a7 | 2011-06-02 22:50:51 +0000 | [diff] [blame] | 8365 | uint32_t shifted = Shift_C(val2, shift_t, shift_n, APSR_C, carry, &success); | 
|  | 8366 | if (!success) | 
|  | 8367 | return false; | 
| Johnny Chen | 2115b41 | 2011-02-21 23:42:44 +0000 | [diff] [blame] | 8368 | uint32_t result = val1 ^ shifted; | 
|  | 8369 |  | 
|  | 8370 | EmulateInstruction::Context context; | 
|  | 8371 | context.type = EmulateInstruction::eContextImmediate; | 
|  | 8372 | context.SetNoArgs (); | 
|  | 8373 |  | 
|  | 8374 | if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry)) | 
|  | 8375 | return false; | 
|  | 8376 | } | 
|  | 8377 | return true; | 
|  | 8378 | } | 
|  | 8379 |  | 
| Johnny Chen | 7c5234d | 2011-02-18 23:41:11 +0000 | [diff] [blame] | 8380 | // Bitwise OR (immediate) performs a bitwise (inclusive) OR of a register value and an immediate value, and | 
|  | 8381 | // writes the result to the destination register.  It can optionally update the condition flags based | 
|  | 8382 | // on the result. | 
|  | 8383 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 8384 | EmulateInstructionARM::EmulateORRImm (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | 7c5234d | 2011-02-18 23:41:11 +0000 | [diff] [blame] | 8385 | { | 
|  | 8386 | #if 0 | 
|  | 8387 | // ARM pseudo code... | 
|  | 8388 | if ConditionPassed() then | 
|  | 8389 | EncodingSpecificOperations(); | 
|  | 8390 | result = R[n] OR imm32; | 
|  | 8391 | if d == 15 then         // Can only occur for ARM encoding | 
|  | 8392 | ALUWritePC(result); // setflags is always FALSE here | 
|  | 8393 | else | 
|  | 8394 | R[d] = result; | 
|  | 8395 | if setflags then | 
|  | 8396 | APSR.N = result<31>; | 
|  | 8397 | APSR.Z = IsZeroBit(result); | 
|  | 8398 | APSR.C = carry; | 
|  | 8399 | // APSR.V unchanged | 
|  | 8400 | #endif | 
|  | 8401 |  | 
|  | 8402 | bool success = false; | 
| Johnny Chen | 7c5234d | 2011-02-18 23:41:11 +0000 | [diff] [blame] | 8403 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 8404 | if (ConditionPassed(opcode)) | 
| Johnny Chen | 7c5234d | 2011-02-18 23:41:11 +0000 | [diff] [blame] | 8405 | { | 
|  | 8406 | uint32_t Rd, Rn; | 
|  | 8407 | uint32_t imm32; // the immediate value to be ORed to the value obtained from Rn | 
|  | 8408 | bool setflags; | 
|  | 8409 | uint32_t carry; // the carry bit after ARM/Thumb Expand operation | 
|  | 8410 | switch (encoding) | 
|  | 8411 | { | 
|  | 8412 | case eEncodingT1: | 
|  | 8413 | Rd = Bits32(opcode, 11, 8); | 
|  | 8414 | Rn = Bits32(opcode, 19, 16); | 
|  | 8415 | setflags = BitIsSet(opcode, 20); | 
|  | 8416 | imm32 = ThumbExpandImm_C(opcode, APSR_C, carry); // (imm32, carry) = ThumbExpandImm(i:imm3:imm8, APSR.C) | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 8417 | // if Rn == '1111' then SEE MOV (immediate); | 
| Johnny Chen | 7c5234d | 2011-02-18 23:41:11 +0000 | [diff] [blame] | 8418 | if (Rn == 15) | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 8419 | return EmulateMOVRdImm (opcode, eEncodingT2); | 
| Johnny Chen | 7c5234d | 2011-02-18 23:41:11 +0000 | [diff] [blame] | 8420 | if (BadReg(Rd) || Rn == 13) | 
|  | 8421 | return false; | 
|  | 8422 | break; | 
|  | 8423 | case eEncodingA1: | 
|  | 8424 | Rd = Bits32(opcode, 15, 12); | 
|  | 8425 | Rn = Bits32(opcode, 19, 16); | 
|  | 8426 | setflags = BitIsSet(opcode, 20); | 
|  | 8427 | imm32 = ARMExpandImm_C(opcode, APSR_C, carry); // (imm32, carry) = ARMExpandImm(imm12, APSR.C) | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 8428 |  | 
| Johnny Chen | 7c5234d | 2011-02-18 23:41:11 +0000 | [diff] [blame] | 8429 | if (Rd == 15 && setflags) | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 8430 | return EmulateSUBSPcLrEtc (opcode, encoding); | 
| Johnny Chen | 7c5234d | 2011-02-18 23:41:11 +0000 | [diff] [blame] | 8431 | break; | 
|  | 8432 | default: | 
|  | 8433 | return false; | 
|  | 8434 | } | 
|  | 8435 |  | 
|  | 8436 | // Read the first operand. | 
|  | 8437 | uint32_t val1 = ReadCoreReg(Rn, &success); | 
|  | 8438 | if (!success) | 
|  | 8439 | return false; | 
|  | 8440 |  | 
|  | 8441 | uint32_t result = val1 | imm32; | 
|  | 8442 |  | 
|  | 8443 | EmulateInstruction::Context context; | 
|  | 8444 | context.type = EmulateInstruction::eContextImmediate; | 
|  | 8445 | context.SetNoArgs (); | 
|  | 8446 |  | 
|  | 8447 | if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry)) | 
|  | 8448 | return false; | 
|  | 8449 | } | 
|  | 8450 | return true; | 
|  | 8451 | } | 
|  | 8452 |  | 
|  | 8453 | // Bitwise OR (register) performs a bitwise (inclusive) OR of a register value and an optionally-shifted register | 
|  | 8454 | // value, and writes the result to the destination register.  It can optionally update the condition flags based | 
|  | 8455 | // on the result. | 
|  | 8456 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 8457 | EmulateInstructionARM::EmulateORRReg (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | 7c5234d | 2011-02-18 23:41:11 +0000 | [diff] [blame] | 8458 | { | 
|  | 8459 | #if 0 | 
|  | 8460 | // ARM pseudo code... | 
|  | 8461 | if ConditionPassed() then | 
|  | 8462 | EncodingSpecificOperations(); | 
|  | 8463 | (shifted, carry) = Shift_C(R[m], shift_t, shift_n, APSR.C); | 
|  | 8464 | result = R[n] OR shifted; | 
|  | 8465 | if d == 15 then         // Can only occur for ARM encoding | 
|  | 8466 | ALUWritePC(result); // setflags is always FALSE here | 
|  | 8467 | else | 
|  | 8468 | R[d] = result; | 
|  | 8469 | if setflags then | 
|  | 8470 | APSR.N = result<31>; | 
|  | 8471 | APSR.Z = IsZeroBit(result); | 
|  | 8472 | APSR.C = carry; | 
|  | 8473 | // APSR.V unchanged | 
|  | 8474 | #endif | 
|  | 8475 |  | 
|  | 8476 | bool success = false; | 
| Johnny Chen | 7c5234d | 2011-02-18 23:41:11 +0000 | [diff] [blame] | 8477 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 8478 | if (ConditionPassed(opcode)) | 
| Johnny Chen | 7c5234d | 2011-02-18 23:41:11 +0000 | [diff] [blame] | 8479 | { | 
|  | 8480 | uint32_t Rd, Rn, Rm; | 
|  | 8481 | ARM_ShifterType shift_t; | 
|  | 8482 | uint32_t shift_n; // the shift applied to the value read from Rm | 
|  | 8483 | bool setflags; | 
|  | 8484 | uint32_t carry; | 
|  | 8485 | switch (encoding) | 
|  | 8486 | { | 
|  | 8487 | case eEncodingT1: | 
|  | 8488 | Rd = Rn = Bits32(opcode, 2, 0); | 
|  | 8489 | Rm = Bits32(opcode, 5, 3); | 
|  | 8490 | setflags = !InITBlock(); | 
|  | 8491 | shift_t = SRType_LSL; | 
|  | 8492 | shift_n = 0; | 
| Johnny Chen | ed32e7c | 2011-02-22 23:42:58 +0000 | [diff] [blame] | 8493 | break; | 
| Johnny Chen | 7c5234d | 2011-02-18 23:41:11 +0000 | [diff] [blame] | 8494 | case eEncodingT2: | 
|  | 8495 | Rd = Bits32(opcode, 11, 8); | 
|  | 8496 | Rn = Bits32(opcode, 19, 16); | 
|  | 8497 | Rm = Bits32(opcode, 3, 0); | 
|  | 8498 | setflags = BitIsSet(opcode, 20); | 
| Johnny Chen | 3dd0605 | 2011-02-22 21:17:52 +0000 | [diff] [blame] | 8499 | shift_n = DecodeImmShiftThumb(opcode, shift_t); | 
|  | 8500 | // if Rn == '1111' then SEE MOV (register); | 
| Johnny Chen | 7c5234d | 2011-02-18 23:41:11 +0000 | [diff] [blame] | 8501 | if (Rn == 15) | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 8502 | return EmulateMOVRdRm (opcode, eEncodingT3); | 
| Johnny Chen | 7c5234d | 2011-02-18 23:41:11 +0000 | [diff] [blame] | 8503 | if (BadReg(Rd) || Rn == 13 || BadReg(Rm)) | 
|  | 8504 | return false; | 
|  | 8505 | break; | 
|  | 8506 | case eEncodingA1: | 
|  | 8507 | Rd = Bits32(opcode, 15, 12); | 
|  | 8508 | Rn = Bits32(opcode, 19, 16); | 
|  | 8509 | Rm = Bits32(opcode, 3, 0); | 
|  | 8510 | setflags = BitIsSet(opcode, 20); | 
| Johnny Chen | 3dd0605 | 2011-02-22 21:17:52 +0000 | [diff] [blame] | 8511 | shift_n = DecodeImmShiftARM(opcode, shift_t); | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 8512 |  | 
| Johnny Chen | 7c5234d | 2011-02-18 23:41:11 +0000 | [diff] [blame] | 8513 | if (Rd == 15 && setflags) | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 8514 | return EmulateSUBSPcLrEtc (opcode, encoding); | 
| Johnny Chen | 7c5234d | 2011-02-18 23:41:11 +0000 | [diff] [blame] | 8515 | break; | 
|  | 8516 | default: | 
|  | 8517 | return false; | 
|  | 8518 | } | 
|  | 8519 |  | 
|  | 8520 | // Read the first operand. | 
|  | 8521 | uint32_t val1 = ReadCoreReg(Rn, &success); | 
|  | 8522 | if (!success) | 
|  | 8523 | return false; | 
|  | 8524 |  | 
|  | 8525 | // Read the second operand. | 
|  | 8526 | uint32_t val2 = ReadCoreReg(Rm, &success); | 
|  | 8527 | if (!success) | 
|  | 8528 | return false; | 
|  | 8529 |  | 
| Johnny Chen | a4438a7 | 2011-06-02 22:50:51 +0000 | [diff] [blame] | 8530 | uint32_t shifted = Shift_C(val2, shift_t, shift_n, APSR_C, carry, &success); | 
|  | 8531 | if (!success) | 
|  | 8532 | return false; | 
| Johnny Chen | 2115b41 | 2011-02-21 23:42:44 +0000 | [diff] [blame] | 8533 | uint32_t result = val1 | shifted; | 
| Johnny Chen | 7c5234d | 2011-02-18 23:41:11 +0000 | [diff] [blame] | 8534 |  | 
|  | 8535 | EmulateInstruction::Context context; | 
|  | 8536 | context.type = EmulateInstruction::eContextImmediate; | 
|  | 8537 | context.SetNoArgs (); | 
|  | 8538 |  | 
|  | 8539 | if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry)) | 
|  | 8540 | return false; | 
|  | 8541 | } | 
|  | 8542 | return true; | 
|  | 8543 | } | 
|  | 8544 |  | 
| Johnny Chen | ed32e7c | 2011-02-22 23:42:58 +0000 | [diff] [blame] | 8545 | // Reverse Subtract (immediate) subtracts a register value from an immediate value, and writes the result to | 
|  | 8546 | // the destination register. It can optionally update the condition flags based on the result. | 
|  | 8547 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 8548 | EmulateInstructionARM::EmulateRSBImm (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | ed32e7c | 2011-02-22 23:42:58 +0000 | [diff] [blame] | 8549 | { | 
|  | 8550 | #if 0 | 
|  | 8551 | // ARM pseudo code... | 
|  | 8552 | if ConditionPassed() then | 
|  | 8553 | EncodingSpecificOperations(); | 
|  | 8554 | (result, carry, overflow) = AddWithCarry(NOT(R[n]), imm32, '1'); | 
|  | 8555 | if d == 15 then         // Can only occur for ARM encoding | 
|  | 8556 | ALUWritePC(result); // setflags is always FALSE here | 
|  | 8557 | else | 
|  | 8558 | R[d] = result; | 
|  | 8559 | if setflags then | 
|  | 8560 | APSR.N = result<31>; | 
|  | 8561 | APSR.Z = IsZeroBit(result); | 
|  | 8562 | APSR.C = carry; | 
|  | 8563 | APSR.V = overflow; | 
|  | 8564 | #endif | 
|  | 8565 |  | 
|  | 8566 | bool success = false; | 
| Johnny Chen | ed32e7c | 2011-02-22 23:42:58 +0000 | [diff] [blame] | 8567 |  | 
|  | 8568 | uint32_t Rd; // the destination register | 
|  | 8569 | uint32_t Rn; // the first operand | 
|  | 8570 | bool setflags; | 
|  | 8571 | uint32_t imm32; // the immediate value to be added to the value obtained from Rn | 
|  | 8572 | switch (encoding) { | 
|  | 8573 | case eEncodingT1: | 
|  | 8574 | Rd = Bits32(opcode, 2, 0); | 
|  | 8575 | Rn = Bits32(opcode, 5, 3); | 
|  | 8576 | setflags = !InITBlock(); | 
|  | 8577 | imm32 = 0; | 
|  | 8578 | break; | 
|  | 8579 | case eEncodingT2: | 
|  | 8580 | Rd = Bits32(opcode, 11, 8); | 
|  | 8581 | Rn = Bits32(opcode, 19, 16); | 
|  | 8582 | setflags = BitIsSet(opcode, 20); | 
|  | 8583 | imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8) | 
|  | 8584 | if (BadReg(Rd) || BadReg(Rn)) | 
|  | 8585 | return false; | 
|  | 8586 | break; | 
|  | 8587 | case eEncodingA1: | 
|  | 8588 | Rd = Bits32(opcode, 15, 12); | 
|  | 8589 | Rn = Bits32(opcode, 19, 16); | 
|  | 8590 | setflags = BitIsSet(opcode, 20); | 
|  | 8591 | imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12) | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 8592 |  | 
| Johnny Chen | ed32e7c | 2011-02-22 23:42:58 +0000 | [diff] [blame] | 8593 | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related instructions; | 
| Johnny Chen | ed32e7c | 2011-02-22 23:42:58 +0000 | [diff] [blame] | 8594 | if (Rd == 15 && setflags) | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 8595 | return EmulateSUBSPcLrEtc (opcode, encoding); | 
| Johnny Chen | ed32e7c | 2011-02-22 23:42:58 +0000 | [diff] [blame] | 8596 | break; | 
|  | 8597 | default: | 
|  | 8598 | return false; | 
|  | 8599 | } | 
|  | 8600 | // Read the register value from the operand register Rn. | 
|  | 8601 | uint32_t reg_val = ReadCoreReg(Rn, &success); | 
|  | 8602 | if (!success) | 
|  | 8603 | return false; | 
|  | 8604 |  | 
|  | 8605 | AddWithCarryResult res = AddWithCarry(~reg_val, imm32, 1); | 
|  | 8606 |  | 
|  | 8607 | EmulateInstruction::Context context; | 
|  | 8608 | context.type = EmulateInstruction::eContextImmediate; | 
|  | 8609 | context.SetNoArgs (); | 
|  | 8610 |  | 
|  | 8611 | if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, res.carry_out, res.overflow)) | 
|  | 8612 | return false; | 
|  | 8613 |  | 
|  | 8614 | return true; | 
|  | 8615 | } | 
|  | 8616 |  | 
|  | 8617 | // Reverse Subtract (register) subtracts a register value from an optionally-shifted register value, and writes the | 
|  | 8618 | // result to the destination register. It can optionally update the condition flags based on the result. | 
|  | 8619 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 8620 | EmulateInstructionARM::EmulateRSBReg (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | ed32e7c | 2011-02-22 23:42:58 +0000 | [diff] [blame] | 8621 | { | 
|  | 8622 | #if 0 | 
|  | 8623 | // ARM pseudo code... | 
|  | 8624 | if ConditionPassed() then | 
|  | 8625 | EncodingSpecificOperations(); | 
|  | 8626 | shifted = Shift(R[m], shift_t, shift_n, APSR.C); | 
|  | 8627 | (result, carry, overflow) = AddWithCarry(NOT(R[n]), shifted, '1'); | 
|  | 8628 | if d == 15 then         // Can only occur for ARM encoding | 
|  | 8629 | ALUWritePC(result); // setflags is always FALSE here | 
|  | 8630 | else | 
|  | 8631 | R[d] = result; | 
|  | 8632 | if setflags then | 
|  | 8633 | APSR.N = result<31>; | 
|  | 8634 | APSR.Z = IsZeroBit(result); | 
|  | 8635 | APSR.C = carry; | 
|  | 8636 | APSR.V = overflow; | 
|  | 8637 | #endif | 
|  | 8638 |  | 
|  | 8639 | bool success = false; | 
| Johnny Chen | ed32e7c | 2011-02-22 23:42:58 +0000 | [diff] [blame] | 8640 |  | 
|  | 8641 | uint32_t Rd; // the destination register | 
|  | 8642 | uint32_t Rn; // the first operand | 
|  | 8643 | uint32_t Rm; // the second operand | 
|  | 8644 | bool setflags; | 
|  | 8645 | ARM_ShifterType shift_t; | 
|  | 8646 | uint32_t shift_n; // the shift applied to the value read from Rm | 
|  | 8647 | switch (encoding) { | 
|  | 8648 | case eEncodingT1: | 
|  | 8649 | Rd = Bits32(opcode, 11, 8); | 
|  | 8650 | Rn = Bits32(opcode, 19, 16); | 
|  | 8651 | Rm = Bits32(opcode, 3, 0); | 
|  | 8652 | setflags = BitIsSet(opcode, 20); | 
|  | 8653 | shift_n = DecodeImmShiftThumb(opcode, shift_t); | 
|  | 8654 | // if (BadReg(d) || BadReg(m)) then UNPREDICTABLE; | 
|  | 8655 | if (BadReg(Rd) || BadReg(Rn) || BadReg(Rm)) | 
|  | 8656 | return false; | 
|  | 8657 | break; | 
|  | 8658 | case eEncodingA1: | 
|  | 8659 | Rd = Bits32(opcode, 15, 12); | 
|  | 8660 | Rn = Bits32(opcode, 19, 16); | 
|  | 8661 | Rm = Bits32(opcode, 3, 0); | 
|  | 8662 | setflags = BitIsSet(opcode, 20); | 
|  | 8663 | shift_n = DecodeImmShiftARM(opcode, shift_t); | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 8664 |  | 
| Johnny Chen | ed32e7c | 2011-02-22 23:42:58 +0000 | [diff] [blame] | 8665 | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related instructions; | 
| Johnny Chen | ed32e7c | 2011-02-22 23:42:58 +0000 | [diff] [blame] | 8666 | if (Rd == 15 && setflags) | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 8667 | return EmulateSUBSPcLrEtc (opcode, encoding); | 
| Johnny Chen | ed32e7c | 2011-02-22 23:42:58 +0000 | [diff] [blame] | 8668 | break; | 
|  | 8669 | default: | 
|  | 8670 | return false; | 
|  | 8671 | } | 
|  | 8672 | // Read the register value from register Rn. | 
|  | 8673 | uint32_t val1 = ReadCoreReg(Rn, &success); | 
|  | 8674 | if (!success) | 
|  | 8675 | return false; | 
|  | 8676 |  | 
|  | 8677 | // Read the register value from register Rm. | 
|  | 8678 | uint32_t val2 = ReadCoreReg(Rm, &success); | 
|  | 8679 | if (!success) | 
|  | 8680 | return false; | 
|  | 8681 |  | 
| Johnny Chen | a4438a7 | 2011-06-02 22:50:51 +0000 | [diff] [blame] | 8682 | uint32_t shifted = Shift(val2, shift_t, shift_n, APSR_C, &success); | 
|  | 8683 | if (!success) | 
|  | 8684 | return false; | 
| Johnny Chen | ed32e7c | 2011-02-22 23:42:58 +0000 | [diff] [blame] | 8685 | AddWithCarryResult res = AddWithCarry(~val1, shifted, 1); | 
|  | 8686 |  | 
|  | 8687 | EmulateInstruction::Context context; | 
|  | 8688 | context.type = EmulateInstruction::eContextImmediate; | 
|  | 8689 | context.SetNoArgs(); | 
|  | 8690 | if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, res.carry_out, res.overflow)) | 
|  | 8691 | return false; | 
|  | 8692 |  | 
|  | 8693 | return true; | 
|  | 8694 | } | 
|  | 8695 |  | 
| Johnny Chen | 90e607b | 2011-02-23 00:07:09 +0000 | [diff] [blame] | 8696 | // Reverse Subtract with Carry (immediate) subtracts a register value and the value of NOT (Carry flag) from | 
|  | 8697 | // an immediate value, and writes the result to the destination register. It can optionally update the condition | 
|  | 8698 | // flags based on the result. | 
|  | 8699 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 8700 | EmulateInstructionARM::EmulateRSCImm (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | 90e607b | 2011-02-23 00:07:09 +0000 | [diff] [blame] | 8701 | { | 
|  | 8702 | #if 0 | 
|  | 8703 | // ARM pseudo code... | 
|  | 8704 | if ConditionPassed() then | 
|  | 8705 | EncodingSpecificOperations(); | 
|  | 8706 | (result, carry, overflow) = AddWithCarry(NOT(R[n]), imm32, APSR.C); | 
|  | 8707 | if d == 15 then | 
|  | 8708 | ALUWritePC(result); // setflags is always FALSE here | 
|  | 8709 | else | 
|  | 8710 | R[d] = result; | 
|  | 8711 | if setflags then | 
|  | 8712 | APSR.N = result<31>; | 
|  | 8713 | APSR.Z = IsZeroBit(result); | 
|  | 8714 | APSR.C = carry; | 
|  | 8715 | APSR.V = overflow; | 
|  | 8716 | #endif | 
|  | 8717 |  | 
|  | 8718 | bool success = false; | 
| Johnny Chen | 90e607b | 2011-02-23 00:07:09 +0000 | [diff] [blame] | 8719 |  | 
|  | 8720 | uint32_t Rd; // the destination register | 
|  | 8721 | uint32_t Rn; // the first operand | 
|  | 8722 | bool setflags; | 
|  | 8723 | uint32_t imm32; // the immediate value to be added to the value obtained from Rn | 
|  | 8724 | switch (encoding) { | 
|  | 8725 | case eEncodingA1: | 
|  | 8726 | Rd = Bits32(opcode, 15, 12); | 
|  | 8727 | Rn = Bits32(opcode, 19, 16); | 
|  | 8728 | setflags = BitIsSet(opcode, 20); | 
|  | 8729 | imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12) | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 8730 |  | 
| Johnny Chen | 90e607b | 2011-02-23 00:07:09 +0000 | [diff] [blame] | 8731 | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related instructions; | 
| Johnny Chen | 90e607b | 2011-02-23 00:07:09 +0000 | [diff] [blame] | 8732 | if (Rd == 15 && setflags) | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 8733 | return EmulateSUBSPcLrEtc  (opcode, encoding); | 
| Johnny Chen | 90e607b | 2011-02-23 00:07:09 +0000 | [diff] [blame] | 8734 | break; | 
|  | 8735 | default: | 
|  | 8736 | return false; | 
|  | 8737 | } | 
|  | 8738 | // Read the register value from the operand register Rn. | 
|  | 8739 | uint32_t reg_val = ReadCoreReg(Rn, &success); | 
|  | 8740 | if (!success) | 
|  | 8741 | return false; | 
|  | 8742 |  | 
|  | 8743 | AddWithCarryResult res = AddWithCarry(~reg_val, imm32, APSR_C); | 
|  | 8744 |  | 
|  | 8745 | EmulateInstruction::Context context; | 
|  | 8746 | context.type = EmulateInstruction::eContextImmediate; | 
|  | 8747 | context.SetNoArgs (); | 
|  | 8748 |  | 
|  | 8749 | if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, res.carry_out, res.overflow)) | 
|  | 8750 | return false; | 
|  | 8751 |  | 
|  | 8752 | return true; | 
|  | 8753 | } | 
|  | 8754 |  | 
|  | 8755 | // Reverse Subtract with Carry (register) subtracts a register value and the value of NOT (Carry flag) from an | 
|  | 8756 | // optionally-shifted register value, and writes the result to the destination register. It can optionally update the | 
|  | 8757 | // condition flags based on the result. | 
|  | 8758 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 8759 | EmulateInstructionARM::EmulateRSCReg (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | 90e607b | 2011-02-23 00:07:09 +0000 | [diff] [blame] | 8760 | { | 
|  | 8761 | #if 0 | 
|  | 8762 | // ARM pseudo code... | 
|  | 8763 | if ConditionPassed() then | 
|  | 8764 | EncodingSpecificOperations(); | 
|  | 8765 | shifted = Shift(R[m], shift_t, shift_n, APSR.C); | 
|  | 8766 | (result, carry, overflow) = AddWithCarry(NOT(R[n]), shifted, APSR.C); | 
|  | 8767 | if d == 15 then | 
|  | 8768 | ALUWritePC(result); // setflags is always FALSE here | 
|  | 8769 | else | 
|  | 8770 | R[d] = result; | 
|  | 8771 | if setflags then | 
|  | 8772 | APSR.N = result<31>; | 
|  | 8773 | APSR.Z = IsZeroBit(result); | 
|  | 8774 | APSR.C = carry; | 
|  | 8775 | APSR.V = overflow; | 
|  | 8776 | #endif | 
|  | 8777 |  | 
|  | 8778 | bool success = false; | 
| Johnny Chen | 90e607b | 2011-02-23 00:07:09 +0000 | [diff] [blame] | 8779 |  | 
|  | 8780 | uint32_t Rd; // the destination register | 
|  | 8781 | uint32_t Rn; // the first operand | 
|  | 8782 | uint32_t Rm; // the second operand | 
|  | 8783 | bool setflags; | 
|  | 8784 | ARM_ShifterType shift_t; | 
|  | 8785 | uint32_t shift_n; // the shift applied to the value read from Rm | 
|  | 8786 | switch (encoding) { | 
|  | 8787 | case eEncodingA1: | 
|  | 8788 | Rd = Bits32(opcode, 15, 12); | 
|  | 8789 | Rn = Bits32(opcode, 19, 16); | 
|  | 8790 | Rm = Bits32(opcode, 3, 0); | 
|  | 8791 | setflags = BitIsSet(opcode, 20); | 
|  | 8792 | shift_n = DecodeImmShiftARM(opcode, shift_t); | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 8793 |  | 
| Johnny Chen | 90e607b | 2011-02-23 00:07:09 +0000 | [diff] [blame] | 8794 | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related instructions; | 
| Johnny Chen | 90e607b | 2011-02-23 00:07:09 +0000 | [diff] [blame] | 8795 | if (Rd == 15 && setflags) | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 8796 | return EmulateSUBSPcLrEtc (opcode, encoding); | 
| Johnny Chen | 90e607b | 2011-02-23 00:07:09 +0000 | [diff] [blame] | 8797 | break; | 
|  | 8798 | default: | 
|  | 8799 | return false; | 
|  | 8800 | } | 
|  | 8801 | // Read the register value from register Rn. | 
|  | 8802 | uint32_t val1 = ReadCoreReg(Rn, &success); | 
|  | 8803 | if (!success) | 
|  | 8804 | return false; | 
|  | 8805 |  | 
|  | 8806 | // Read the register value from register Rm. | 
|  | 8807 | uint32_t val2 = ReadCoreReg(Rm, &success); | 
|  | 8808 | if (!success) | 
|  | 8809 | return false; | 
|  | 8810 |  | 
| Johnny Chen | a4438a7 | 2011-06-02 22:50:51 +0000 | [diff] [blame] | 8811 | uint32_t shifted = Shift(val2, shift_t, shift_n, APSR_C, &success); | 
|  | 8812 | if (!success) | 
|  | 8813 | return false; | 
| Johnny Chen | 90e607b | 2011-02-23 00:07:09 +0000 | [diff] [blame] | 8814 | AddWithCarryResult res = AddWithCarry(~val1, shifted, APSR_C); | 
|  | 8815 |  | 
|  | 8816 | EmulateInstruction::Context context; | 
|  | 8817 | context.type = EmulateInstruction::eContextImmediate; | 
|  | 8818 | context.SetNoArgs(); | 
|  | 8819 | if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, res.carry_out, res.overflow)) | 
|  | 8820 | return false; | 
|  | 8821 |  | 
|  | 8822 | return true; | 
|  | 8823 | } | 
|  | 8824 |  | 
| Johnny Chen | 9b38177 | 2011-02-23 01:01:21 +0000 | [diff] [blame] | 8825 | // Subtract with Carry (immediate) subtracts an immediate value and the value of | 
|  | 8826 | // NOT (Carry flag) from a register value, and writes the result to the destination register. | 
|  | 8827 | // It can optionally update the condition flags based on the result. | 
|  | 8828 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 8829 | EmulateInstructionARM::EmulateSBCImm (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | 9b38177 | 2011-02-23 01:01:21 +0000 | [diff] [blame] | 8830 | { | 
|  | 8831 | #if 0 | 
|  | 8832 | // ARM pseudo code... | 
|  | 8833 | if ConditionPassed() then | 
|  | 8834 | EncodingSpecificOperations(); | 
| Johnny Chen | 15a7a6b | 2011-02-23 23:47:56 +0000 | [diff] [blame] | 8835 | (result, carry, overflow) = AddWithCarry(R[n], NOT(imm32), APSR.C); | 
| Johnny Chen | 9b38177 | 2011-02-23 01:01:21 +0000 | [diff] [blame] | 8836 | if d == 15 then         // Can only occur for ARM encoding | 
|  | 8837 | ALUWritePC(result); // setflags is always FALSE here | 
|  | 8838 | else | 
|  | 8839 | R[d] = result; | 
|  | 8840 | if setflags then | 
|  | 8841 | APSR.N = result<31>; | 
|  | 8842 | APSR.Z = IsZeroBit(result); | 
|  | 8843 | APSR.C = carry; | 
|  | 8844 | APSR.V = overflow; | 
|  | 8845 | #endif | 
|  | 8846 |  | 
|  | 8847 | bool success = false; | 
| Johnny Chen | 9b38177 | 2011-02-23 01:01:21 +0000 | [diff] [blame] | 8848 |  | 
|  | 8849 | uint32_t Rd; // the destination register | 
|  | 8850 | uint32_t Rn; // the first operand | 
|  | 8851 | bool setflags; | 
|  | 8852 | uint32_t imm32; // the immediate value to be added to the value obtained from Rn | 
|  | 8853 | switch (encoding) { | 
|  | 8854 | case eEncodingT1: | 
|  | 8855 | Rd = Bits32(opcode, 11, 8); | 
|  | 8856 | Rn = Bits32(opcode, 19, 16); | 
|  | 8857 | setflags = BitIsSet(opcode, 20); | 
|  | 8858 | imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8) | 
|  | 8859 | if (BadReg(Rd) || BadReg(Rn)) | 
|  | 8860 | return false; | 
|  | 8861 | break; | 
|  | 8862 | case eEncodingA1: | 
|  | 8863 | Rd = Bits32(opcode, 15, 12); | 
|  | 8864 | Rn = Bits32(opcode, 19, 16); | 
|  | 8865 | setflags = BitIsSet(opcode, 20); | 
|  | 8866 | imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12) | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 8867 |  | 
| Johnny Chen | 9b38177 | 2011-02-23 01:01:21 +0000 | [diff] [blame] | 8868 | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related instructions; | 
| Johnny Chen | 9b38177 | 2011-02-23 01:01:21 +0000 | [diff] [blame] | 8869 | if (Rd == 15 && setflags) | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 8870 | return EmulateSUBSPcLrEtc (opcode, encoding); | 
| Johnny Chen | 9b38177 | 2011-02-23 01:01:21 +0000 | [diff] [blame] | 8871 | break; | 
|  | 8872 | default: | 
|  | 8873 | return false; | 
|  | 8874 | } | 
|  | 8875 | // Read the register value from the operand register Rn. | 
|  | 8876 | uint32_t reg_val = ReadCoreReg(Rn, &success); | 
|  | 8877 | if (!success) | 
|  | 8878 | return false; | 
|  | 8879 |  | 
|  | 8880 | AddWithCarryResult res = AddWithCarry(reg_val, ~imm32, APSR_C); | 
|  | 8881 |  | 
|  | 8882 | EmulateInstruction::Context context; | 
|  | 8883 | context.type = EmulateInstruction::eContextImmediate; | 
|  | 8884 | context.SetNoArgs (); | 
|  | 8885 |  | 
|  | 8886 | if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, res.carry_out, res.overflow)) | 
|  | 8887 | return false; | 
|  | 8888 |  | 
|  | 8889 | return true; | 
|  | 8890 | } | 
|  | 8891 |  | 
|  | 8892 | // Subtract with Carry (register) subtracts an optionally-shifted register value and the value of | 
|  | 8893 | // NOT (Carry flag) from a register value, and writes the result to the destination register. | 
|  | 8894 | // It can optionally update the condition flags based on the result. | 
|  | 8895 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 8896 | EmulateInstructionARM::EmulateSBCReg (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | 9b38177 | 2011-02-23 01:01:21 +0000 | [diff] [blame] | 8897 | { | 
|  | 8898 | #if 0 | 
|  | 8899 | // ARM pseudo code... | 
|  | 8900 | if ConditionPassed() then | 
|  | 8901 | EncodingSpecificOperations(); | 
|  | 8902 | shifted = Shift(R[m], shift_t, shift_n, APSR.C); | 
|  | 8903 | (result, carry, overflow) = AddWithCarry(R[n], NOT(shifted), APSR.C); | 
|  | 8904 | if d == 15 then         // Can only occur for ARM encoding | 
|  | 8905 | ALUWritePC(result); // setflags is always FALSE here | 
|  | 8906 | else | 
|  | 8907 | R[d] = result; | 
|  | 8908 | if setflags then | 
|  | 8909 | APSR.N = result<31>; | 
|  | 8910 | APSR.Z = IsZeroBit(result); | 
|  | 8911 | APSR.C = carry; | 
|  | 8912 | APSR.V = overflow; | 
|  | 8913 | #endif | 
|  | 8914 |  | 
|  | 8915 | bool success = false; | 
| Johnny Chen | 9b38177 | 2011-02-23 01:01:21 +0000 | [diff] [blame] | 8916 |  | 
|  | 8917 | uint32_t Rd; // the destination register | 
|  | 8918 | uint32_t Rn; // the first operand | 
|  | 8919 | uint32_t Rm; // the second operand | 
|  | 8920 | bool setflags; | 
|  | 8921 | ARM_ShifterType shift_t; | 
|  | 8922 | uint32_t shift_n; // the shift applied to the value read from Rm | 
|  | 8923 | switch (encoding) { | 
|  | 8924 | case eEncodingT1: | 
|  | 8925 | Rd = Rn = Bits32(opcode, 2, 0); | 
|  | 8926 | Rm = Bits32(opcode, 5, 3); | 
|  | 8927 | setflags = !InITBlock(); | 
|  | 8928 | shift_t = SRType_LSL; | 
|  | 8929 | shift_n = 0; | 
|  | 8930 | break; | 
|  | 8931 | case eEncodingT2: | 
|  | 8932 | Rd = Bits32(opcode, 11, 8); | 
|  | 8933 | Rn = Bits32(opcode, 19, 16); | 
|  | 8934 | Rm = Bits32(opcode, 3, 0); | 
|  | 8935 | setflags = BitIsSet(opcode, 20); | 
|  | 8936 | shift_n = DecodeImmShiftThumb(opcode, shift_t); | 
|  | 8937 | if (BadReg(Rd) || BadReg(Rn) || BadReg(Rm)) | 
|  | 8938 | return false; | 
|  | 8939 | break; | 
|  | 8940 | case eEncodingA1: | 
|  | 8941 | Rd = Bits32(opcode, 15, 12); | 
|  | 8942 | Rn = Bits32(opcode, 19, 16); | 
|  | 8943 | Rm = Bits32(opcode, 3, 0); | 
|  | 8944 | setflags = BitIsSet(opcode, 20); | 
|  | 8945 | shift_n = DecodeImmShiftARM(opcode, shift_t); | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 8946 |  | 
| Johnny Chen | 9b38177 | 2011-02-23 01:01:21 +0000 | [diff] [blame] | 8947 | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related instructions; | 
| Johnny Chen | 9b38177 | 2011-02-23 01:01:21 +0000 | [diff] [blame] | 8948 | if (Rd == 15 && setflags) | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 8949 | return EmulateSUBSPcLrEtc (opcode, encoding); | 
| Johnny Chen | 9b38177 | 2011-02-23 01:01:21 +0000 | [diff] [blame] | 8950 | break; | 
|  | 8951 | default: | 
|  | 8952 | return false; | 
|  | 8953 | } | 
|  | 8954 | // Read the register value from register Rn. | 
|  | 8955 | uint32_t val1 = ReadCoreReg(Rn, &success); | 
|  | 8956 | if (!success) | 
|  | 8957 | return false; | 
|  | 8958 |  | 
|  | 8959 | // Read the register value from register Rm. | 
|  | 8960 | uint32_t val2 = ReadCoreReg(Rm, &success); | 
|  | 8961 | if (!success) | 
|  | 8962 | return false; | 
|  | 8963 |  | 
| Johnny Chen | a4438a7 | 2011-06-02 22:50:51 +0000 | [diff] [blame] | 8964 | uint32_t shifted = Shift(val2, shift_t, shift_n, APSR_C, &success); | 
|  | 8965 | if (!success) | 
|  | 8966 | return false; | 
| Johnny Chen | 9b38177 | 2011-02-23 01:01:21 +0000 | [diff] [blame] | 8967 | AddWithCarryResult res = AddWithCarry(val1, ~shifted, APSR_C); | 
|  | 8968 |  | 
|  | 8969 | EmulateInstruction::Context context; | 
|  | 8970 | context.type = EmulateInstruction::eContextImmediate; | 
|  | 8971 | context.SetNoArgs(); | 
|  | 8972 | if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, res.carry_out, res.overflow)) | 
|  | 8973 | return false; | 
|  | 8974 |  | 
|  | 8975 | return true; | 
|  | 8976 | } | 
|  | 8977 |  | 
| Johnny Chen | 15a7a6b | 2011-02-23 23:47:56 +0000 | [diff] [blame] | 8978 | // This instruction subtracts an immediate value from a register value, and writes the result | 
|  | 8979 | // to the destination register.  It can optionally update the condition flags based on the result. | 
|  | 8980 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 8981 | EmulateInstructionARM::EmulateSUBImmThumb (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | 15a7a6b | 2011-02-23 23:47:56 +0000 | [diff] [blame] | 8982 | { | 
|  | 8983 | #if 0 | 
|  | 8984 | // ARM pseudo code... | 
|  | 8985 | if ConditionPassed() then | 
|  | 8986 | EncodingSpecificOperations(); | 
|  | 8987 | (result, carry, overflow) = AddWithCarry(R[n], NOT(imm32), '1'); | 
|  | 8988 | R[d] = result; | 
|  | 8989 | if setflags then | 
|  | 8990 | APSR.N = result<31>; | 
|  | 8991 | APSR.Z = IsZeroBit(result); | 
|  | 8992 | APSR.C = carry; | 
|  | 8993 | APSR.V = overflow; | 
|  | 8994 | #endif | 
|  | 8995 |  | 
|  | 8996 | bool success = false; | 
| Johnny Chen | 15a7a6b | 2011-02-23 23:47:56 +0000 | [diff] [blame] | 8997 |  | 
|  | 8998 | uint32_t Rd; // the destination register | 
|  | 8999 | uint32_t Rn; // the first operand | 
|  | 9000 | bool setflags; | 
|  | 9001 | uint32_t imm32; // the immediate value to be subtracted from the value obtained from Rn | 
|  | 9002 | switch (encoding) { | 
|  | 9003 | case eEncodingT1: | 
|  | 9004 | Rd = Bits32(opcode, 2, 0); | 
|  | 9005 | Rn = Bits32(opcode, 5, 3); | 
|  | 9006 | setflags = !InITBlock(); | 
|  | 9007 | imm32 = Bits32(opcode, 8, 6); // imm32 = ZeroExtend(imm3, 32) | 
|  | 9008 | break; | 
|  | 9009 | case eEncodingT2: | 
|  | 9010 | Rd = Rn = Bits32(opcode, 10, 8); | 
|  | 9011 | setflags = !InITBlock(); | 
|  | 9012 | imm32 = Bits32(opcode, 7, 0); // imm32 = ZeroExtend(imm8, 32) | 
|  | 9013 | break; | 
|  | 9014 | case eEncodingT3: | 
|  | 9015 | Rd = Bits32(opcode, 11, 8); | 
|  | 9016 | Rn = Bits32(opcode, 19, 16); | 
|  | 9017 | setflags = BitIsSet(opcode, 20); | 
|  | 9018 | imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8) | 
|  | 9019 |  | 
|  | 9020 | // if Rd == '1111' && S == '1' then SEE CMP (immediate); | 
|  | 9021 | if (Rd == 15 && setflags) | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 9022 | return EmulateCMPImm (opcode, eEncodingT2); | 
| Johnny Chen | 15a7a6b | 2011-02-23 23:47:56 +0000 | [diff] [blame] | 9023 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 9024 | // if Rn == '1101' then SEE SUB (SP minus immediate); | 
| Johnny Chen | 15a7a6b | 2011-02-23 23:47:56 +0000 | [diff] [blame] | 9025 | if (Rn == 13) | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 9026 | return EmulateSUBSPImm (opcode, eEncodingT2); | 
| Johnny Chen | 15a7a6b | 2011-02-23 23:47:56 +0000 | [diff] [blame] | 9027 |  | 
|  | 9028 | // if d == 13 || (d == 15 && S == '0') || n == 15 then UNPREDICTABLE; | 
|  | 9029 | if (Rd == 13 || (Rd == 15 && !setflags) || Rn == 15) | 
|  | 9030 | return false; | 
|  | 9031 | break; | 
|  | 9032 | case eEncodingT4: | 
|  | 9033 | Rd = Bits32(opcode, 11, 8); | 
|  | 9034 | Rn = Bits32(opcode, 19, 16); | 
|  | 9035 | setflags = BitIsSet(opcode, 20); | 
|  | 9036 | imm32 = ThumbImm12(opcode); // imm32 = ZeroExtend(i:imm3:imm8, 32) | 
|  | 9037 |  | 
|  | 9038 | // if Rn == '1111' then SEE ADR; | 
|  | 9039 | if (Rn == 15) | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 9040 | return EmulateADR (opcode, eEncodingT2); | 
| Johnny Chen | 15a7a6b | 2011-02-23 23:47:56 +0000 | [diff] [blame] | 9041 |  | 
|  | 9042 | // if Rn == '1101' then SEE SUB (SP minus immediate); | 
|  | 9043 | if (Rn == 13) | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 9044 | return EmulateSUBSPImm (opcode, eEncodingT3); | 
| Johnny Chen | 15a7a6b | 2011-02-23 23:47:56 +0000 | [diff] [blame] | 9045 |  | 
|  | 9046 | if (BadReg(Rd)) | 
|  | 9047 | return false; | 
|  | 9048 | break; | 
|  | 9049 | default: | 
|  | 9050 | return false; | 
|  | 9051 | } | 
|  | 9052 | // Read the register value from the operand register Rn. | 
|  | 9053 | uint32_t reg_val = ReadCoreReg(Rn, &success); | 
|  | 9054 | if (!success) | 
|  | 9055 | return false; | 
|  | 9056 |  | 
|  | 9057 | AddWithCarryResult res = AddWithCarry(reg_val, ~imm32, 1); | 
|  | 9058 |  | 
|  | 9059 | EmulateInstruction::Context context; | 
|  | 9060 | context.type = EmulateInstruction::eContextImmediate; | 
|  | 9061 | context.SetNoArgs (); | 
|  | 9062 |  | 
|  | 9063 | if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, res.carry_out, res.overflow)) | 
|  | 9064 | return false; | 
|  | 9065 |  | 
|  | 9066 | return true; | 
|  | 9067 | } | 
|  | 9068 |  | 
|  | 9069 | // This instruction subtracts an immediate value from a register value, and writes the result | 
|  | 9070 | // to the destination register.  It can optionally update the condition flags based on the result. | 
|  | 9071 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 9072 | EmulateInstructionARM::EmulateSUBImmARM (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | 15a7a6b | 2011-02-23 23:47:56 +0000 | [diff] [blame] | 9073 | { | 
|  | 9074 | #if 0 | 
|  | 9075 | // ARM pseudo code... | 
|  | 9076 | if ConditionPassed() then | 
|  | 9077 | EncodingSpecificOperations(); | 
|  | 9078 | (result, carry, overflow) = AddWithCarry(R[n], NOT(imm32), '1'); | 
|  | 9079 | if d == 15 then | 
|  | 9080 | ALUWritePC(result); // setflags is always FALSE here | 
|  | 9081 | else | 
|  | 9082 | R[d] = result; | 
|  | 9083 | if setflags then | 
|  | 9084 | APSR.N = result<31>; | 
|  | 9085 | APSR.Z = IsZeroBit(result); | 
|  | 9086 | APSR.C = carry; | 
|  | 9087 | APSR.V = overflow; | 
|  | 9088 | #endif | 
|  | 9089 |  | 
|  | 9090 | bool success = false; | 
| Johnny Chen | 15a7a6b | 2011-02-23 23:47:56 +0000 | [diff] [blame] | 9091 |  | 
|  | 9092 | uint32_t Rd; // the destination register | 
|  | 9093 | uint32_t Rn; // the first operand | 
|  | 9094 | bool setflags; | 
|  | 9095 | uint32_t imm32; // the immediate value to be subtracted from the value obtained from Rn | 
|  | 9096 | switch (encoding) { | 
|  | 9097 | case eEncodingA1: | 
|  | 9098 | Rd = Bits32(opcode, 15, 12); | 
|  | 9099 | Rn = Bits32(opcode, 19, 16); | 
|  | 9100 | setflags = BitIsSet(opcode, 20); | 
|  | 9101 | imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12) | 
|  | 9102 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 9103 | // if Rn == '1111' && S == '0' then SEE ADR; | 
| Johnny Chen | 15a7a6b | 2011-02-23 23:47:56 +0000 | [diff] [blame] | 9104 | if (Rn == 15 && !setflags) | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 9105 | return EmulateADR (opcode, eEncodingA2); | 
| Johnny Chen | 15a7a6b | 2011-02-23 23:47:56 +0000 | [diff] [blame] | 9106 |  | 
| Caroline Tice | bb48f0b | 2011-03-28 16:10:45 +0000 | [diff] [blame] | 9107 | // if Rn == '1101' then SEE SUB (SP minus immediate); | 
| Johnny Chen | 15a7a6b | 2011-02-23 23:47:56 +0000 | [diff] [blame] | 9108 | if (Rn == 13) | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 9109 | return EmulateSUBSPImm (opcode, eEncodingA1); | 
| Johnny Chen | 15a7a6b | 2011-02-23 23:47:56 +0000 | [diff] [blame] | 9110 |  | 
|  | 9111 | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related instructions; | 
| Johnny Chen | 15a7a6b | 2011-02-23 23:47:56 +0000 | [diff] [blame] | 9112 | if (Rd == 15 && setflags) | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 9113 | return EmulateSUBSPcLrEtc (opcode, encoding); | 
| Johnny Chen | 15a7a6b | 2011-02-23 23:47:56 +0000 | [diff] [blame] | 9114 | break; | 
|  | 9115 | default: | 
|  | 9116 | return false; | 
|  | 9117 | } | 
|  | 9118 | // Read the register value from the operand register Rn. | 
|  | 9119 | uint32_t reg_val = ReadCoreReg(Rn, &success); | 
|  | 9120 | if (!success) | 
|  | 9121 | return false; | 
|  | 9122 |  | 
|  | 9123 | AddWithCarryResult res = AddWithCarry(reg_val, ~imm32, 1); | 
|  | 9124 |  | 
|  | 9125 | EmulateInstruction::Context context; | 
|  | 9126 | context.type = EmulateInstruction::eContextImmediate; | 
|  | 9127 | context.SetNoArgs (); | 
|  | 9128 |  | 
|  | 9129 | if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, res.carry_out, res.overflow)) | 
|  | 9130 | return false; | 
|  | 9131 |  | 
|  | 9132 | return true; | 
|  | 9133 | } | 
|  | 9134 |  | 
| Johnny Chen | 2115b41 | 2011-02-21 23:42:44 +0000 | [diff] [blame] | 9135 | // Test Equivalence (immediate) performs a bitwise exclusive OR operation on a register value and an | 
|  | 9136 | // immediate value.  It updates the condition flags based on the result, and discards the result. | 
|  | 9137 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 9138 | EmulateInstructionARM::EmulateTEQImm (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | 2115b41 | 2011-02-21 23:42:44 +0000 | [diff] [blame] | 9139 | { | 
|  | 9140 | #if 0 | 
|  | 9141 | // ARM pseudo code... | 
|  | 9142 | if ConditionPassed() then | 
|  | 9143 | EncodingSpecificOperations(); | 
|  | 9144 | result = R[n] EOR imm32; | 
|  | 9145 | APSR.N = result<31>; | 
|  | 9146 | APSR.Z = IsZeroBit(result); | 
|  | 9147 | APSR.C = carry; | 
|  | 9148 | // APSR.V unchanged | 
|  | 9149 | #endif | 
|  | 9150 |  | 
|  | 9151 | bool success = false; | 
| Johnny Chen | 2115b41 | 2011-02-21 23:42:44 +0000 | [diff] [blame] | 9152 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 9153 | if (ConditionPassed(opcode)) | 
| Johnny Chen | 2115b41 | 2011-02-21 23:42:44 +0000 | [diff] [blame] | 9154 | { | 
|  | 9155 | uint32_t Rn; | 
|  | 9156 | uint32_t imm32; // the immediate value to be ANDed to the value obtained from Rn | 
|  | 9157 | uint32_t carry; // the carry bit after ARM/Thumb Expand operation | 
|  | 9158 | switch (encoding) | 
|  | 9159 | { | 
|  | 9160 | case eEncodingT1: | 
|  | 9161 | Rn = Bits32(opcode, 19, 16); | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 9162 | imm32 = ThumbExpandImm_C (opcode, APSR_C, carry); // (imm32, carry) = ThumbExpandImm(i:imm3:imm8, APSR.C) | 
| Johnny Chen | 2115b41 | 2011-02-21 23:42:44 +0000 | [diff] [blame] | 9163 | if (BadReg(Rn)) | 
|  | 9164 | return false; | 
|  | 9165 | break; | 
|  | 9166 | case eEncodingA1: | 
|  | 9167 | Rn = Bits32(opcode, 19, 16); | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 9168 | imm32 = ARMExpandImm_C (opcode, APSR_C, carry); // (imm32, carry) = ARMExpandImm(imm12, APSR.C) | 
| Johnny Chen | 2115b41 | 2011-02-21 23:42:44 +0000 | [diff] [blame] | 9169 | break; | 
|  | 9170 | default: | 
|  | 9171 | return false; | 
|  | 9172 | } | 
|  | 9173 |  | 
|  | 9174 | // Read the first operand. | 
|  | 9175 | uint32_t val1 = ReadCoreReg(Rn, &success); | 
|  | 9176 | if (!success) | 
|  | 9177 | return false; | 
|  | 9178 |  | 
|  | 9179 | uint32_t result = val1 ^ imm32; | 
|  | 9180 |  | 
|  | 9181 | EmulateInstruction::Context context; | 
|  | 9182 | context.type = EmulateInstruction::eContextImmediate; | 
|  | 9183 | context.SetNoArgs (); | 
|  | 9184 |  | 
|  | 9185 | if (!WriteFlags(context, result, carry)) | 
|  | 9186 | return false; | 
|  | 9187 | } | 
|  | 9188 | return true; | 
|  | 9189 | } | 
|  | 9190 |  | 
|  | 9191 | // Test Equivalence (register) performs a bitwise exclusive OR operation on a register value and an | 
|  | 9192 | // optionally-shifted register value.  It updates the condition flags based on the result, and discards | 
|  | 9193 | // the result. | 
|  | 9194 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 9195 | EmulateInstructionARM::EmulateTEQReg (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | 2115b41 | 2011-02-21 23:42:44 +0000 | [diff] [blame] | 9196 | { | 
|  | 9197 | #if 0 | 
|  | 9198 | // ARM pseudo code... | 
|  | 9199 | if ConditionPassed() then | 
|  | 9200 | EncodingSpecificOperations(); | 
|  | 9201 | (shifted, carry) = Shift_C(R[m], shift_t, shift_n, APSR.C); | 
|  | 9202 | result = R[n] EOR shifted; | 
|  | 9203 | APSR.N = result<31>; | 
|  | 9204 | APSR.Z = IsZeroBit(result); | 
|  | 9205 | APSR.C = carry; | 
|  | 9206 | // APSR.V unchanged | 
|  | 9207 | #endif | 
|  | 9208 |  | 
|  | 9209 | bool success = false; | 
| Johnny Chen | 2115b41 | 2011-02-21 23:42:44 +0000 | [diff] [blame] | 9210 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 9211 | if (ConditionPassed(opcode)) | 
| Johnny Chen | 2115b41 | 2011-02-21 23:42:44 +0000 | [diff] [blame] | 9212 | { | 
|  | 9213 | uint32_t Rn, Rm; | 
|  | 9214 | ARM_ShifterType shift_t; | 
|  | 9215 | uint32_t shift_n; // the shift applied to the value read from Rm | 
|  | 9216 | uint32_t carry; | 
|  | 9217 | switch (encoding) | 
|  | 9218 | { | 
|  | 9219 | case eEncodingT1: | 
|  | 9220 | Rn = Bits32(opcode, 19, 16); | 
|  | 9221 | Rm = Bits32(opcode, 3, 0); | 
| Johnny Chen | 3dd0605 | 2011-02-22 21:17:52 +0000 | [diff] [blame] | 9222 | shift_n = DecodeImmShiftThumb(opcode, shift_t); | 
| Johnny Chen | 2115b41 | 2011-02-21 23:42:44 +0000 | [diff] [blame] | 9223 | if (BadReg(Rn) || BadReg(Rm)) | 
|  | 9224 | return false; | 
|  | 9225 | break; | 
|  | 9226 | case eEncodingA1: | 
|  | 9227 | Rn = Bits32(opcode, 19, 16); | 
|  | 9228 | Rm = Bits32(opcode, 3, 0); | 
| Johnny Chen | 3dd0605 | 2011-02-22 21:17:52 +0000 | [diff] [blame] | 9229 | shift_n = DecodeImmShiftARM(opcode, shift_t); | 
| Johnny Chen | 2115b41 | 2011-02-21 23:42:44 +0000 | [diff] [blame] | 9230 | break; | 
|  | 9231 | default: | 
|  | 9232 | return false; | 
|  | 9233 | } | 
|  | 9234 |  | 
|  | 9235 | // Read the first operand. | 
|  | 9236 | uint32_t val1 = ReadCoreReg(Rn, &success); | 
|  | 9237 | if (!success) | 
|  | 9238 | return false; | 
|  | 9239 |  | 
|  | 9240 | // Read the second operand. | 
|  | 9241 | uint32_t val2 = ReadCoreReg(Rm, &success); | 
|  | 9242 | if (!success) | 
|  | 9243 | return false; | 
|  | 9244 |  | 
| Johnny Chen | a4438a7 | 2011-06-02 22:50:51 +0000 | [diff] [blame] | 9245 | uint32_t shifted = Shift_C(val2, shift_t, shift_n, APSR_C, carry, &success); | 
|  | 9246 | if (!success) | 
|  | 9247 | return false; | 
| Johnny Chen | 2115b41 | 2011-02-21 23:42:44 +0000 | [diff] [blame] | 9248 | uint32_t result = val1 ^ shifted; | 
|  | 9249 |  | 
|  | 9250 | EmulateInstruction::Context context; | 
|  | 9251 | context.type = EmulateInstruction::eContextImmediate; | 
|  | 9252 | context.SetNoArgs (); | 
|  | 9253 |  | 
|  | 9254 | if (!WriteFlags(context, result, carry)) | 
|  | 9255 | return false; | 
|  | 9256 | } | 
|  | 9257 | return true; | 
|  | 9258 | } | 
|  | 9259 |  | 
| Johnny Chen | de3cce3 | 2011-02-21 21:24:49 +0000 | [diff] [blame] | 9260 | // Test (immediate) performs a bitwise AND operation on a register value and an immediate value. | 
|  | 9261 | // It updates the condition flags based on the result, and discards the result. | 
|  | 9262 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 9263 | EmulateInstructionARM::EmulateTSTImm (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | de3cce3 | 2011-02-21 21:24:49 +0000 | [diff] [blame] | 9264 | { | 
|  | 9265 | #if 0 | 
|  | 9266 | // ARM pseudo code... | 
|  | 9267 | if ConditionPassed() then | 
|  | 9268 | EncodingSpecificOperations(); | 
|  | 9269 | result = R[n] AND imm32; | 
|  | 9270 | APSR.N = result<31>; | 
|  | 9271 | APSR.Z = IsZeroBit(result); | 
|  | 9272 | APSR.C = carry; | 
|  | 9273 | // APSR.V unchanged | 
|  | 9274 | #endif | 
|  | 9275 |  | 
|  | 9276 | bool success = false; | 
| Johnny Chen | de3cce3 | 2011-02-21 21:24:49 +0000 | [diff] [blame] | 9277 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 9278 | if (ConditionPassed(opcode)) | 
| Johnny Chen | de3cce3 | 2011-02-21 21:24:49 +0000 | [diff] [blame] | 9279 | { | 
|  | 9280 | uint32_t Rn; | 
|  | 9281 | uint32_t imm32; // the immediate value to be ANDed to the value obtained from Rn | 
|  | 9282 | uint32_t carry; // the carry bit after ARM/Thumb Expand operation | 
|  | 9283 | switch (encoding) | 
|  | 9284 | { | 
|  | 9285 | case eEncodingT1: | 
|  | 9286 | Rn = Bits32(opcode, 19, 16); | 
|  | 9287 | imm32 = ThumbExpandImm_C(opcode, APSR_C, carry); // (imm32, carry) = ThumbExpandImm(i:imm3:imm8, APSR.C) | 
|  | 9288 | if (BadReg(Rn)) | 
|  | 9289 | return false; | 
|  | 9290 | break; | 
|  | 9291 | case eEncodingA1: | 
|  | 9292 | Rn = Bits32(opcode, 19, 16); | 
|  | 9293 | imm32 = ARMExpandImm_C(opcode, APSR_C, carry); // (imm32, carry) = ARMExpandImm(imm12, APSR.C) | 
|  | 9294 | break; | 
|  | 9295 | default: | 
|  | 9296 | return false; | 
|  | 9297 | } | 
|  | 9298 |  | 
|  | 9299 | // Read the first operand. | 
|  | 9300 | uint32_t val1 = ReadCoreReg(Rn, &success); | 
|  | 9301 | if (!success) | 
|  | 9302 | return false; | 
|  | 9303 |  | 
|  | 9304 | uint32_t result = val1 & imm32; | 
|  | 9305 |  | 
|  | 9306 | EmulateInstruction::Context context; | 
|  | 9307 | context.type = EmulateInstruction::eContextImmediate; | 
|  | 9308 | context.SetNoArgs (); | 
|  | 9309 |  | 
|  | 9310 | if (!WriteFlags(context, result, carry)) | 
|  | 9311 | return false; | 
|  | 9312 | } | 
|  | 9313 | return true; | 
|  | 9314 | } | 
|  | 9315 |  | 
|  | 9316 | // Test (register) performs a bitwise AND operation on a register value and an optionally-shifted register value. | 
|  | 9317 | // It updates the condition flags based on the result, and discards the result. | 
|  | 9318 | bool | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 9319 | EmulateInstructionARM::EmulateTSTReg (const uint32_t opcode, const ARMEncoding encoding) | 
| Johnny Chen | de3cce3 | 2011-02-21 21:24:49 +0000 | [diff] [blame] | 9320 | { | 
|  | 9321 | #if 0 | 
|  | 9322 | // ARM pseudo code... | 
|  | 9323 | if ConditionPassed() then | 
|  | 9324 | EncodingSpecificOperations(); | 
|  | 9325 | (shifted, carry) = Shift_C(R[m], shift_t, shift_n, APSR.C); | 
|  | 9326 | result = R[n] AND shifted; | 
|  | 9327 | APSR.N = result<31>; | 
|  | 9328 | APSR.Z = IsZeroBit(result); | 
|  | 9329 | APSR.C = carry; | 
|  | 9330 | // APSR.V unchanged | 
|  | 9331 | #endif | 
|  | 9332 |  | 
|  | 9333 | bool success = false; | 
| Johnny Chen | de3cce3 | 2011-02-21 21:24:49 +0000 | [diff] [blame] | 9334 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 9335 | if (ConditionPassed(opcode)) | 
| Johnny Chen | de3cce3 | 2011-02-21 21:24:49 +0000 | [diff] [blame] | 9336 | { | 
|  | 9337 | uint32_t Rn, Rm; | 
|  | 9338 | ARM_ShifterType shift_t; | 
|  | 9339 | uint32_t shift_n; // the shift applied to the value read from Rm | 
|  | 9340 | uint32_t carry; | 
|  | 9341 | switch (encoding) | 
|  | 9342 | { | 
|  | 9343 | case eEncodingT1: | 
|  | 9344 | Rn = Bits32(opcode, 2, 0); | 
|  | 9345 | Rm = Bits32(opcode, 5, 3); | 
|  | 9346 | shift_t = SRType_LSL; | 
|  | 9347 | shift_n = 0; | 
| Johnny Chen | ed32e7c | 2011-02-22 23:42:58 +0000 | [diff] [blame] | 9348 | break; | 
| Johnny Chen | de3cce3 | 2011-02-21 21:24:49 +0000 | [diff] [blame] | 9349 | case eEncodingT2: | 
|  | 9350 | Rn = Bits32(opcode, 19, 16); | 
|  | 9351 | Rm = Bits32(opcode, 3, 0); | 
| Johnny Chen | 3dd0605 | 2011-02-22 21:17:52 +0000 | [diff] [blame] | 9352 | shift_n = DecodeImmShiftThumb(opcode, shift_t); | 
| Johnny Chen | de3cce3 | 2011-02-21 21:24:49 +0000 | [diff] [blame] | 9353 | if (BadReg(Rn) || BadReg(Rm)) | 
|  | 9354 | return false; | 
|  | 9355 | break; | 
|  | 9356 | case eEncodingA1: | 
|  | 9357 | Rn = Bits32(opcode, 19, 16); | 
|  | 9358 | Rm = Bits32(opcode, 3, 0); | 
| Johnny Chen | 3dd0605 | 2011-02-22 21:17:52 +0000 | [diff] [blame] | 9359 | shift_n = DecodeImmShiftARM(opcode, shift_t); | 
| Johnny Chen | de3cce3 | 2011-02-21 21:24:49 +0000 | [diff] [blame] | 9360 | break; | 
|  | 9361 | default: | 
|  | 9362 | return false; | 
|  | 9363 | } | 
|  | 9364 |  | 
|  | 9365 | // Read the first operand. | 
|  | 9366 | uint32_t val1 = ReadCoreReg(Rn, &success); | 
|  | 9367 | if (!success) | 
|  | 9368 | return false; | 
|  | 9369 |  | 
|  | 9370 | // Read the second operand. | 
|  | 9371 | uint32_t val2 = ReadCoreReg(Rm, &success); | 
|  | 9372 | if (!success) | 
|  | 9373 | return false; | 
|  | 9374 |  | 
| Johnny Chen | a4438a7 | 2011-06-02 22:50:51 +0000 | [diff] [blame] | 9375 | uint32_t shifted = Shift_C(val2, shift_t, shift_n, APSR_C, carry, &success); | 
|  | 9376 | if (!success) | 
|  | 9377 | return false; | 
| Johnny Chen | de3cce3 | 2011-02-21 21:24:49 +0000 | [diff] [blame] | 9378 | uint32_t result = val1 & shifted; | 
|  | 9379 |  | 
|  | 9380 | EmulateInstruction::Context context; | 
|  | 9381 | context.type = EmulateInstruction::eContextImmediate; | 
|  | 9382 | context.SetNoArgs (); | 
|  | 9383 |  | 
|  | 9384 | if (!WriteFlags(context, result, carry)) | 
|  | 9385 | return false; | 
|  | 9386 | } | 
|  | 9387 | return true; | 
|  | 9388 | } | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 9389 |  | 
|  | 9390 | // A8.6.216 SUB (SP minus register) | 
|  | 9391 | bool | 
|  | 9392 | EmulateInstructionARM::EmulateSUBSPReg (const uint32_t opcode, const ARMEncoding encoding) | 
|  | 9393 | { | 
|  | 9394 | #if 0 | 
|  | 9395 | if ConditionPassed() then | 
|  | 9396 | EncodingSpecificOperations(); | 
|  | 9397 | shifted = Shift(R[m], shift_t, shift_n, APSR.C); | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 9398 | (result, carry, overflow) = AddWithCarry(SP, NOT(shifted), Ô1Õ); | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 9399 | if d == 15 then // Can only occur for ARM encoding | 
|  | 9400 | ALUWritePC(result); // setflags is always FALSE here | 
|  | 9401 | else | 
|  | 9402 | R[d] = result; | 
|  | 9403 | if setflags then | 
|  | 9404 | APSR.N = result<31>; | 
|  | 9405 | APSR.Z = IsZeroBit(result); | 
|  | 9406 | APSR.C = carry; | 
|  | 9407 | APSR.V = overflow; | 
|  | 9408 | #endif | 
|  | 9409 |  | 
|  | 9410 | bool success = false; | 
|  | 9411 |  | 
|  | 9412 | if (ConditionPassed(opcode)) | 
|  | 9413 | { | 
|  | 9414 | uint32_t d; | 
|  | 9415 | uint32_t m; | 
|  | 9416 | bool setflags; | 
|  | 9417 | ARM_ShifterType shift_t; | 
|  | 9418 | uint32_t shift_n; | 
|  | 9419 |  | 
|  | 9420 | switch (encoding) | 
|  | 9421 | { | 
|  | 9422 | case eEncodingT1: | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 9423 | // d = UInt(Rd); m = UInt(Rm); setflags = (S == Ô1Õ); | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 9424 | d = Bits32 (opcode, 11, 8); | 
|  | 9425 | m = Bits32 (opcode, 3, 0); | 
|  | 9426 | setflags = BitIsSet (opcode, 20); | 
|  | 9427 |  | 
|  | 9428 | // (shift_t, shift_n) = DecodeImmShift(type, imm3:imm2); | 
|  | 9429 | shift_n = DecodeImmShiftThumb (opcode, shift_t); | 
|  | 9430 |  | 
|  | 9431 | // if d == 13 && (shift_t != SRType_LSL || shift_n > 3) then UNPREDICTABLE; | 
|  | 9432 | if ((d == 13) && ((shift_t != SRType_LSL) || (shift_n > 3))) | 
|  | 9433 | return false; | 
|  | 9434 |  | 
|  | 9435 | // if d == 15 || BadReg(m) then UNPREDICTABLE; | 
|  | 9436 | if ((d == 15) || BadReg (m)) | 
|  | 9437 | return false; | 
|  | 9438 | break; | 
|  | 9439 |  | 
|  | 9440 | case eEncodingA1: | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 9441 | // d = UInt(Rd); m = UInt(Rm); setflags = (S == Ô1Õ); | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 9442 | d = Bits32 (opcode, 15, 12); | 
|  | 9443 | m = Bits32 (opcode, 3, 0); | 
|  | 9444 | setflags = BitIsSet (opcode, 20); | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 9445 |  | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 9446 | // if Rd == Ô1111Õ && S == Ô1Õ then SEE SUBS PC, LR and related instructions; | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 9447 | if (d == 15 && setflags) | 
|  | 9448 | EmulateSUBSPcLrEtc (opcode, encoding); | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 9449 |  | 
|  | 9450 | // (shift_t, shift_n) = DecodeImmShift(type, imm5); | 
|  | 9451 | shift_n = DecodeImmShiftARM (opcode, shift_t); | 
|  | 9452 | break; | 
|  | 9453 |  | 
|  | 9454 | default: | 
|  | 9455 | return false; | 
|  | 9456 | } | 
|  | 9457 |  | 
|  | 9458 | // shifted = Shift(R[m], shift_t, shift_n, APSR.C); | 
|  | 9459 | uint32_t Rm = ReadCoreReg (m, &success); | 
|  | 9460 | if (!success) | 
|  | 9461 | return false; | 
|  | 9462 |  | 
| Johnny Chen | a4438a7 | 2011-06-02 22:50:51 +0000 | [diff] [blame] | 9463 | uint32_t shifted = Shift (Rm, shift_t, shift_n, APSR_C, &success); | 
|  | 9464 | if (!success) | 
|  | 9465 | return false; | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 9466 |  | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 9467 | // (result, carry, overflow) = AddWithCarry(SP, NOT(shifted), Ô1Õ); | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 9468 | uint32_t sp_val = ReadCoreReg (SP_REG, &success); | 
|  | 9469 | if (!success) | 
|  | 9470 | return false; | 
|  | 9471 |  | 
|  | 9472 | AddWithCarryResult res = AddWithCarry (sp_val, ~shifted, 1); | 
|  | 9473 |  | 
|  | 9474 | EmulateInstruction::Context context; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 9475 | context.type = eContextArithmetic; | 
|  | 9476 | RegisterInfo sp_reg; | 
|  | 9477 | GetRegisterInfo (eRegisterKindDWARF, dwarf_sp, sp_reg); | 
|  | 9478 | RegisterInfo dwarf_reg; | 
|  | 9479 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + m, dwarf_reg); | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 9480 | context.SetRegisterRegisterOperands (sp_reg, dwarf_reg); | 
|  | 9481 |  | 
| Caroline Tice | ef44000 | 2011-03-30 05:40:56 +0000 | [diff] [blame] | 9482 | if (!WriteCoreRegOptionalFlags(context, res.result, dwarf_r0 + d, setflags, res.carry_out, res.overflow)) | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 9483 | return false; | 
|  | 9484 | } | 
|  | 9485 | return true; | 
|  | 9486 | } | 
|  | 9487 |  | 
|  | 9488 |  | 
|  | 9489 | // A8.6.7 ADD (register-shifted register) | 
|  | 9490 | bool | 
| Caroline Tice | c08ed38 | 2011-03-29 23:03:16 +0000 | [diff] [blame] | 9491 | EmulateInstructionARM::EmulateADDRegShift (const uint32_t opcode, const ARMEncoding encoding) | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 9492 | { | 
|  | 9493 | #if 0 | 
| Caroline Tice | c08ed38 | 2011-03-29 23:03:16 +0000 | [diff] [blame] | 9494 | if ConditionPassed() then | 
|  | 9495 | EncodingSpecificOperations(); | 
|  | 9496 | shift_n = UInt(R[s]<7:0>); | 
|  | 9497 | shifted = Shift(R[m], shift_t, shift_n, APSR.C); | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 9498 | (result, carry, overflow) = AddWithCarry(R[n], shifted, Ô0Õ); | 
| Caroline Tice | c08ed38 | 2011-03-29 23:03:16 +0000 | [diff] [blame] | 9499 | R[d] = result; | 
|  | 9500 | if setflags then | 
|  | 9501 | APSR.N = result<31>; | 
|  | 9502 | APSR.Z = IsZeroBit(result); | 
|  | 9503 | APSR.C = carry; | 
|  | 9504 | APSR.V = overflow; | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 9505 | #endif | 
|  | 9506 |  | 
| Caroline Tice | c08ed38 | 2011-03-29 23:03:16 +0000 | [diff] [blame] | 9507 | bool success = false; | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 9508 |  | 
|  | 9509 | if (ConditionPassed(opcode)) | 
|  | 9510 | { | 
| Caroline Tice | c08ed38 | 2011-03-29 23:03:16 +0000 | [diff] [blame] | 9511 | uint32_t d; | 
|  | 9512 | uint32_t n; | 
|  | 9513 | uint32_t m; | 
|  | 9514 | uint32_t s; | 
|  | 9515 | bool setflags; | 
|  | 9516 | ARM_ShifterType shift_t; | 
|  | 9517 |  | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 9518 | switch (encoding) | 
|  | 9519 | { | 
| Caroline Tice | c08ed38 | 2011-03-29 23:03:16 +0000 | [diff] [blame] | 9520 | case eEncodingA1: | 
|  | 9521 | // d = UInt(Rd); n = UInt(Rn); m = UInt(Rm); s = UInt(Rs); | 
|  | 9522 | d = Bits32 (opcode, 15, 12); | 
|  | 9523 | n = Bits32 (opcode, 19, 16); | 
|  | 9524 | m = Bits32 (opcode, 3, 0); | 
|  | 9525 | s = Bits32 (opcode, 11, 8); | 
|  | 9526 |  | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 9527 | // setflags = (S == Ô1Õ); shift_t = DecodeRegShift(type); | 
| Caroline Tice | c08ed38 | 2011-03-29 23:03:16 +0000 | [diff] [blame] | 9528 | setflags = BitIsSet (opcode, 20); | 
|  | 9529 | shift_t = DecodeRegShift (Bits32 (opcode, 6, 5)); | 
|  | 9530 |  | 
|  | 9531 | // if d == 15 || n == 15 || m == 15 || s == 15 then UNPREDICTABLE; | 
|  | 9532 | if ((d == 15) || (m == 15) || (m == 15) || (s == 15)) | 
|  | 9533 | return false; | 
|  | 9534 | break; | 
|  | 9535 |  | 
|  | 9536 | default: | 
|  | 9537 | return false; | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 9538 | } | 
| Caroline Tice | c08ed38 | 2011-03-29 23:03:16 +0000 | [diff] [blame] | 9539 |  | 
|  | 9540 | // shift_n = UInt(R[s]<7:0>); | 
|  | 9541 | uint32_t Rs = ReadCoreReg (s, &success); | 
|  | 9542 | if (!success) | 
|  | 9543 | return false; | 
|  | 9544 |  | 
|  | 9545 | uint32_t shift_n = Bits32 (Rs, 7, 0); | 
|  | 9546 |  | 
|  | 9547 | // shifted = Shift(R[m], shift_t, shift_n, APSR.C); | 
|  | 9548 | uint32_t Rm = ReadCoreReg (m, &success); | 
|  | 9549 | if (!success) | 
|  | 9550 | return false; | 
|  | 9551 |  | 
| Johnny Chen | a4438a7 | 2011-06-02 22:50:51 +0000 | [diff] [blame] | 9552 | uint32_t shifted = Shift (Rm, shift_t, shift_n, APSR_C, &success); | 
|  | 9553 | if (!success) | 
|  | 9554 | return false; | 
|  | 9555 |  | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 9556 | // (result, carry, overflow) = AddWithCarry(R[n], shifted, Ô0Õ); | 
| Caroline Tice | c08ed38 | 2011-03-29 23:03:16 +0000 | [diff] [blame] | 9557 | uint32_t Rn = ReadCoreReg (n, &success); | 
|  | 9558 | if (!success) | 
|  | 9559 | return false; | 
|  | 9560 |  | 
|  | 9561 | AddWithCarryResult res = AddWithCarry (Rn, shifted, 0); | 
|  | 9562 |  | 
|  | 9563 | // R[d] = result; | 
|  | 9564 | EmulateInstruction::Context context; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 9565 | context.type = eContextArithmetic; | 
|  | 9566 | RegisterInfo reg_n; | 
|  | 9567 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, reg_n); | 
|  | 9568 | RegisterInfo reg_m; | 
|  | 9569 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + m, reg_m); | 
| Caroline Tice | c08ed38 | 2011-03-29 23:03:16 +0000 | [diff] [blame] | 9570 |  | 
|  | 9571 | context.SetRegisterRegisterOperands (reg_n, reg_m); | 
|  | 9572 |  | 
|  | 9573 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + d, res.result)) | 
|  | 9574 | return false; | 
|  | 9575 |  | 
|  | 9576 | // if setflags then | 
|  | 9577 | // APSR.N = result<31>; | 
|  | 9578 | // APSR.Z = IsZeroBit(result); | 
|  | 9579 | // APSR.C = carry; | 
|  | 9580 | // APSR.V = overflow; | 
|  | 9581 | if (setflags) | 
|  | 9582 | return WriteFlags (context, res.result, res.carry_out, res.overflow); | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 9583 | } | 
|  | 9584 | return true; | 
|  | 9585 | } | 
|  | 9586 |  | 
|  | 9587 | // A8.6.213 SUB (register) | 
|  | 9588 | bool | 
|  | 9589 | EmulateInstructionARM::EmulateSUBReg (const uint32_t opcode, const ARMEncoding encoding) | 
|  | 9590 | { | 
|  | 9591 | #if 0 | 
| Caroline Tice | 4cccd53 | 2011-03-29 23:44:20 +0000 | [diff] [blame] | 9592 | if ConditionPassed() then | 
|  | 9593 | EncodingSpecificOperations(); | 
|  | 9594 | shifted = Shift(R[m], shift_t, shift_n, APSR.C); | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 9595 | (result, carry, overflow) = AddWithCarry(R[n], NOT(shifted), Ô1Õ); | 
| Caroline Tice | 4cccd53 | 2011-03-29 23:44:20 +0000 | [diff] [blame] | 9596 | if d == 15 then // Can only occur for ARM encoding | 
|  | 9597 | ALUWritePC(result); // setflags is always FALSE here | 
|  | 9598 | else | 
|  | 9599 | R[d] = result; | 
|  | 9600 | if setflags then | 
|  | 9601 | APSR.N = result<31>; | 
|  | 9602 | APSR.Z = IsZeroBit(result); | 
|  | 9603 | APSR.C = carry; | 
|  | 9604 | APSR.V = overflow; | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 9605 | #endif | 
|  | 9606 |  | 
| Caroline Tice | 4cccd53 | 2011-03-29 23:44:20 +0000 | [diff] [blame] | 9607 | bool success = false; | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 9608 |  | 
|  | 9609 | if (ConditionPassed(opcode)) | 
|  | 9610 | { | 
| Caroline Tice | 4cccd53 | 2011-03-29 23:44:20 +0000 | [diff] [blame] | 9611 | uint32_t d; | 
|  | 9612 | uint32_t n; | 
|  | 9613 | uint32_t m; | 
|  | 9614 | bool setflags; | 
|  | 9615 | ARM_ShifterType shift_t; | 
|  | 9616 | uint32_t shift_n; | 
|  | 9617 |  | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 9618 | switch (encoding) | 
|  | 9619 | { | 
| Caroline Tice | 4cccd53 | 2011-03-29 23:44:20 +0000 | [diff] [blame] | 9620 | case eEncodingT1: | 
|  | 9621 | // d = UInt(Rd); n = UInt(Rn); m = UInt(Rm); setflags = !InITBlock(); | 
|  | 9622 | d = Bits32 (opcode, 2, 0); | 
|  | 9623 | n = Bits32 (opcode, 5, 3); | 
|  | 9624 | m = Bits32 (opcode, 8, 6); | 
|  | 9625 | setflags = !InITBlock(); | 
|  | 9626 |  | 
|  | 9627 | // (shift_t, shift_n) = (SRType_LSL, 0); | 
|  | 9628 | shift_t = SRType_LSL; | 
|  | 9629 | shift_n = 0; | 
|  | 9630 |  | 
|  | 9631 | break; | 
|  | 9632 |  | 
|  | 9633 | case eEncodingT2: | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 9634 | // if Rd == Ô1111Õ && S == Ô1Õ then SEE CMP (register); | 
|  | 9635 | // if Rn == Ô1101Õ then SEE SUB (SP minus register); | 
|  | 9636 | // d = UInt(Rd); n = UInt(Rn); m = UInt(Rm); setflags = (S == Ô1Õ); | 
| Caroline Tice | 4cccd53 | 2011-03-29 23:44:20 +0000 | [diff] [blame] | 9637 | d = Bits32 (opcode, 11, 8); | 
|  | 9638 | n = Bits32 (opcode, 19, 16); | 
|  | 9639 | m = Bits32 (opcode, 3, 0); | 
|  | 9640 | setflags = BitIsSet (opcode, 20); | 
|  | 9641 |  | 
|  | 9642 | // (shift_t, shift_n) = DecodeImmShift(type, imm3:imm2); | 
|  | 9643 | shift_n = DecodeImmShiftThumb (opcode, shift_t); | 
|  | 9644 |  | 
|  | 9645 | // if d == 13 || (d == 15 && S == '0') || n == 15 || BadReg(m) then UNPREDICTABLE; | 
|  | 9646 | if ((d == 13) || ((d == 15) && BitIsClear (opcode, 20)) || (n == 15) || BadReg (m)) | 
|  | 9647 | return false; | 
|  | 9648 |  | 
|  | 9649 | break; | 
|  | 9650 |  | 
|  | 9651 | case eEncodingA1: | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 9652 | // if Rn == Ô1101Õ then SEE SUB (SP minus register); | 
|  | 9653 | // d = UInt(Rd); n = UInt(Rn); m = UInt(Rm); setflags = (S == Ô1Õ); | 
| Caroline Tice | 4cccd53 | 2011-03-29 23:44:20 +0000 | [diff] [blame] | 9654 | d = Bits32 (opcode, 15, 12); | 
|  | 9655 | n = Bits32 (opcode, 19, 16); | 
|  | 9656 | m = Bits32 (opcode, 3, 0); | 
|  | 9657 | setflags = BitIsSet (opcode, 20); | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 9658 |  | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 9659 | // if Rd == Ô1111Õ && S == Ô1Õ then SEE SUBS PC, LR and related instructions; | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 9660 | if ((d == 15) && setflags) | 
|  | 9661 | EmulateSUBSPcLrEtc (opcode, encoding); | 
| Caroline Tice | 4cccd53 | 2011-03-29 23:44:20 +0000 | [diff] [blame] | 9662 |  | 
|  | 9663 | // (shift_t, shift_n) = DecodeImmShift(type, imm5); | 
|  | 9664 | shift_n = DecodeImmShiftARM (opcode, shift_t); | 
|  | 9665 |  | 
|  | 9666 | break; | 
|  | 9667 |  | 
|  | 9668 | default: | 
|  | 9669 | return false; | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 9670 | } | 
| Caroline Tice | 4cccd53 | 2011-03-29 23:44:20 +0000 | [diff] [blame] | 9671 |  | 
|  | 9672 | // shifted = Shift(R[m], shift_t, shift_n, APSR.C); | 
|  | 9673 | uint32_t Rm = ReadCoreReg (m, &success); | 
|  | 9674 | if (!success) | 
|  | 9675 | return false; | 
|  | 9676 |  | 
| Johnny Chen | a4438a7 | 2011-06-02 22:50:51 +0000 | [diff] [blame] | 9677 | uint32_t shifted = Shift (Rm, shift_t, shift_n, APSR_C, &success); | 
|  | 9678 | if (!success) | 
|  | 9679 | return false; | 
| Caroline Tice | 4cccd53 | 2011-03-29 23:44:20 +0000 | [diff] [blame] | 9680 |  | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 9681 | // (result, carry, overflow) = AddWithCarry(R[n], NOT(shifted), Ô1Õ); | 
| Caroline Tice | 4cccd53 | 2011-03-29 23:44:20 +0000 | [diff] [blame] | 9682 | uint32_t Rn = ReadCoreReg (n, &success); | 
|  | 9683 | if (!success) | 
|  | 9684 | return false; | 
|  | 9685 |  | 
|  | 9686 | AddWithCarryResult res = AddWithCarry (Rn, ~shifted, 1); | 
|  | 9687 |  | 
|  | 9688 | // if d == 15 then // Can only occur for ARM encoding | 
|  | 9689 | // ALUWritePC(result); // setflags is always FALSE here | 
|  | 9690 | // else | 
|  | 9691 | // R[d] = result; | 
|  | 9692 | // if setflags then | 
|  | 9693 | // APSR.N = result<31>; | 
|  | 9694 | // APSR.Z = IsZeroBit(result); | 
|  | 9695 | // APSR.C = carry; | 
|  | 9696 | // APSR.V = overflow; | 
|  | 9697 |  | 
|  | 9698 | EmulateInstruction::Context context; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 9699 | context.type = eContextArithmetic; | 
|  | 9700 | RegisterInfo reg_n; | 
|  | 9701 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, reg_n); | 
|  | 9702 | RegisterInfo reg_m; | 
|  | 9703 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + m, reg_m); | 
| Caroline Tice | 4cccd53 | 2011-03-29 23:44:20 +0000 | [diff] [blame] | 9704 | context.SetRegisterRegisterOperands (reg_n, reg_m); | 
|  | 9705 |  | 
| Caroline Tice | ef44000 | 2011-03-30 05:40:56 +0000 | [diff] [blame] | 9706 | if (!WriteCoreRegOptionalFlags (context, res.result, dwarf_r0 + d, setflags, res.carry_out, res.overflow)) | 
| Caroline Tice | 4cccd53 | 2011-03-29 23:44:20 +0000 | [diff] [blame] | 9707 | return false; | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 9708 | } | 
|  | 9709 | return true; | 
|  | 9710 | } | 
| Caroline Tice | 4cccd53 | 2011-03-29 23:44:20 +0000 | [diff] [blame] | 9711 |  | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 9712 | // A8.6.202 STREX | 
| Caroline Tice | 5168b6c | 2011-03-30 05:15:46 +0000 | [diff] [blame] | 9713 | // Store Register Exclusive calculates an address from a base register value and an immediate offset, and stores a | 
|  | 9714 | // word from a register to memory if the executing processor has exclusive access to the memory addressed. | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 9715 | bool | 
|  | 9716 | EmulateInstructionARM::EmulateSTREX (const uint32_t opcode, const ARMEncoding encoding) | 
|  | 9717 | { | 
|  | 9718 | #if 0 | 
| Caroline Tice | 5168b6c | 2011-03-30 05:15:46 +0000 | [diff] [blame] | 9719 | if ConditionPassed() then | 
|  | 9720 | EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | 9721 | address = R[n] + imm32; | 
|  | 9722 | if ExclusiveMonitorsPass(address,4) then | 
|  | 9723 | MemA[address,4] = R[t]; | 
|  | 9724 | R[d] = 0; | 
|  | 9725 | else | 
|  | 9726 | R[d] = 1; | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 9727 | #endif | 
|  | 9728 |  | 
| Caroline Tice | 5168b6c | 2011-03-30 05:15:46 +0000 | [diff] [blame] | 9729 | bool success = false; | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 9730 |  | 
|  | 9731 | if (ConditionPassed(opcode)) | 
|  | 9732 | { | 
| Caroline Tice | 5168b6c | 2011-03-30 05:15:46 +0000 | [diff] [blame] | 9733 | uint32_t d; | 
|  | 9734 | uint32_t t; | 
|  | 9735 | uint32_t n; | 
|  | 9736 | uint32_t imm32; | 
|  | 9737 | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  | 9738 |  | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 9739 | switch (encoding) | 
|  | 9740 | { | 
| Caroline Tice | 5168b6c | 2011-03-30 05:15:46 +0000 | [diff] [blame] | 9741 | case eEncodingT1: | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 9742 | // d = UInt(Rd); t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8:Õ00Õ, 32); | 
| Caroline Tice | 5168b6c | 2011-03-30 05:15:46 +0000 | [diff] [blame] | 9743 | d = Bits32 (opcode, 11, 8); | 
|  | 9744 | t = Bits32 (opcode, 15, 12); | 
|  | 9745 | n = Bits32 (opcode, 19, 16); | 
|  | 9746 | imm32 = Bits32 (opcode, 7, 0) << 2; | 
|  | 9747 |  | 
|  | 9748 | // if BadReg(d) || BadReg(t) || n == 15 then UNPREDICTABLE; | 
|  | 9749 | if (BadReg (d) || BadReg (t) || (n == 15)) | 
|  | 9750 | return false; | 
|  | 9751 |  | 
|  | 9752 | // if d == n || d == t then UNPREDICTABLE; | 
|  | 9753 | if ((d == n) || (d == t)) | 
|  | 9754 | return false; | 
|  | 9755 |  | 
|  | 9756 | break; | 
|  | 9757 |  | 
|  | 9758 | case eEncodingA1: | 
|  | 9759 | // d = UInt(Rd); t = UInt(Rt); n = UInt(Rn); imm32 = Zeros(32); // Zero offset | 
|  | 9760 | d = Bits32 (opcode, 15, 12); | 
|  | 9761 | t = Bits32 (opcode, 3, 0); | 
|  | 9762 | n = Bits32 (opcode, 19, 16); | 
|  | 9763 | imm32 = 0; | 
|  | 9764 |  | 
|  | 9765 | // if d == 15 || t == 15 || n == 15 then UNPREDICTABLE; | 
|  | 9766 | if ((d == 15) || (t == 15) || (n == 15)) | 
|  | 9767 | return false; | 
|  | 9768 |  | 
|  | 9769 | // if d == n || d == t then UNPREDICTABLE; | 
|  | 9770 | if ((d == n) || (d == t)) | 
|  | 9771 | return false; | 
|  | 9772 |  | 
|  | 9773 | break; | 
|  | 9774 |  | 
|  | 9775 | default: | 
|  | 9776 | return false; | 
|  | 9777 | } | 
|  | 9778 |  | 
|  | 9779 | // address = R[n] + imm32; | 
|  | 9780 | uint32_t Rn = ReadCoreReg (n, &success); | 
|  | 9781 | if (!success) | 
|  | 9782 | return false; | 
|  | 9783 |  | 
|  | 9784 | addr_t address = Rn + imm32; | 
|  | 9785 |  | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 9786 | RegisterInfo base_reg; | 
|  | 9787 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
|  | 9788 | RegisterInfo data_reg; | 
|  | 9789 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + t, data_reg); | 
| Caroline Tice | 5168b6c | 2011-03-30 05:15:46 +0000 | [diff] [blame] | 9790 | EmulateInstruction::Context context; | 
|  | 9791 | context.type = eContextRegisterStore; | 
|  | 9792 | context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, imm32); | 
|  | 9793 |  | 
|  | 9794 | // if ExclusiveMonitorsPass(address,4) then | 
|  | 9795 | // if (ExclusiveMonitorsPass (address, addr_byte_size)) -- For now, for the sake of emulation, we will say this | 
|  | 9796 | //                                                         always return true. | 
|  | 9797 | if (true) | 
|  | 9798 | { | 
|  | 9799 | // MemA[address,4] = R[t]; | 
|  | 9800 | uint32_t Rt = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + t, 0, &success); | 
|  | 9801 | if (!success) | 
|  | 9802 | return false; | 
|  | 9803 |  | 
|  | 9804 | if (!MemAWrite (context, address, Rt, addr_byte_size)) | 
|  | 9805 | return false; | 
|  | 9806 |  | 
|  | 9807 | // R[d] = 0; | 
|  | 9808 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, 0)) | 
|  | 9809 | return false; | 
|  | 9810 | } | 
|  | 9811 | else | 
|  | 9812 | { | 
|  | 9813 | // R[d] = 1; | 
|  | 9814 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, 1)) | 
|  | 9815 | return false; | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 9816 | } | 
|  | 9817 | } | 
|  | 9818 | return true; | 
|  | 9819 | } | 
|  | 9820 |  | 
|  | 9821 | // A8.6.197 STRB (immediate, ARM) | 
|  | 9822 | bool | 
|  | 9823 | EmulateInstructionARM::EmulateSTRBImmARM (const uint32_t opcode, const ARMEncoding encoding) | 
|  | 9824 | { | 
|  | 9825 | #if 0 | 
| Caroline Tice | ef44000 | 2011-03-30 05:40:56 +0000 | [diff] [blame] | 9826 | if ConditionPassed() then | 
|  | 9827 | EncodingSpecificOperations(); | 
|  | 9828 | offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | 9829 | address = if index then offset_addr else R[n]; | 
|  | 9830 | MemU[address,1] = R[t]<7:0>; | 
|  | 9831 | if wback then R[n] = offset_addr; | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 9832 | #endif | 
|  | 9833 |  | 
| Caroline Tice | ef44000 | 2011-03-30 05:40:56 +0000 | [diff] [blame] | 9834 | bool success = false; | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 9835 |  | 
|  | 9836 | if (ConditionPassed(opcode)) | 
|  | 9837 | { | 
| Caroline Tice | ef44000 | 2011-03-30 05:40:56 +0000 | [diff] [blame] | 9838 | uint32_t t; | 
|  | 9839 | uint32_t n; | 
|  | 9840 | uint32_t imm32; | 
|  | 9841 | bool index; | 
|  | 9842 | bool add; | 
|  | 9843 | bool wback; | 
|  | 9844 |  | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 9845 | switch (encoding) | 
|  | 9846 | { | 
| Caroline Tice | ef44000 | 2011-03-30 05:40:56 +0000 | [diff] [blame] | 9847 | case eEncodingA1: | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 9848 | // if P == Ô0Õ && W == Ô1Õ then SEE STRBT; | 
| Caroline Tice | ef44000 | 2011-03-30 05:40:56 +0000 | [diff] [blame] | 9849 | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32); | 
|  | 9850 | t = Bits32 (opcode, 15, 12); | 
|  | 9851 | n = Bits32 (opcode, 19, 16); | 
|  | 9852 | imm32 = Bits32 (opcode, 11, 0); | 
|  | 9853 |  | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 9854 | // index = (P == Ô1Õ); add = (U == Ô1Õ); wback = (P == Ô0Õ) || (W == Ô1Õ); | 
| Caroline Tice | ef44000 | 2011-03-30 05:40:56 +0000 | [diff] [blame] | 9855 | index = BitIsSet (opcode, 24); | 
|  | 9856 | add = BitIsSet (opcode, 23); | 
|  | 9857 | wback = BitIsClear (opcode, 24) || BitIsSet (opcode, 21); | 
|  | 9858 |  | 
|  | 9859 | // if t == 15 then UNPREDICTABLE; | 
|  | 9860 | if (t == 15) | 
|  | 9861 | return false; | 
|  | 9862 |  | 
|  | 9863 | // if wback && (n == 15 || n == t) then UNPREDICTABLE; | 
|  | 9864 | if (wback && ((n == 15) || (n == t))) | 
|  | 9865 | return false; | 
|  | 9866 |  | 
|  | 9867 | break; | 
|  | 9868 |  | 
|  | 9869 | default: | 
|  | 9870 | return false; | 
|  | 9871 | } | 
|  | 9872 |  | 
|  | 9873 | // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | 9874 | uint32_t Rn = ReadCoreReg (n, &success); | 
|  | 9875 | if (!success) | 
|  | 9876 | return false; | 
|  | 9877 |  | 
|  | 9878 | addr_t offset_addr; | 
|  | 9879 | if (add) | 
|  | 9880 | offset_addr = Rn + imm32; | 
|  | 9881 | else | 
|  | 9882 | offset_addr = Rn - imm32; | 
|  | 9883 |  | 
|  | 9884 | // address = if index then offset_addr else R[n]; | 
|  | 9885 | addr_t address; | 
|  | 9886 | if (index) | 
|  | 9887 | address = offset_addr; | 
|  | 9888 | else | 
|  | 9889 | address = Rn; | 
|  | 9890 |  | 
|  | 9891 | // MemU[address,1] = R[t]<7:0>; | 
|  | 9892 | uint32_t Rt = ReadCoreReg (t, &success); | 
|  | 9893 | if (!success) | 
|  | 9894 | return false; | 
|  | 9895 |  | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 9896 | RegisterInfo base_reg; | 
|  | 9897 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
|  | 9898 | RegisterInfo data_reg; | 
|  | 9899 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + t, data_reg); | 
| Caroline Tice | ef44000 | 2011-03-30 05:40:56 +0000 | [diff] [blame] | 9900 | EmulateInstruction::Context context; | 
|  | 9901 | context.type = eContextRegisterStore; | 
|  | 9902 | context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, address - Rn); | 
|  | 9903 |  | 
|  | 9904 | if (!MemUWrite (context, address, Bits32 (Rt, 7, 0), 1)) | 
|  | 9905 | return false; | 
|  | 9906 |  | 
|  | 9907 | // if wback then R[n] = offset_addr; | 
|  | 9908 | if (wback) | 
|  | 9909 | { | 
| Caroline Tice | 523c554 | 2011-04-13 00:42:12 +0000 | [diff] [blame] | 9910 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr)) | 
| Caroline Tice | ef44000 | 2011-03-30 05:40:56 +0000 | [diff] [blame] | 9911 | return false; | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 9912 | } | 
|  | 9913 | } | 
|  | 9914 | return true; | 
|  | 9915 | } | 
|  | 9916 |  | 
|  | 9917 | // A8.6.194 STR (immediate, ARM) | 
|  | 9918 | bool | 
|  | 9919 | EmulateInstructionARM::EmulateSTRImmARM (const uint32_t opcode, const ARMEncoding encoding) | 
|  | 9920 | { | 
|  | 9921 | #if 0 | 
| Caroline Tice | d42b3cc | 2011-03-30 06:03:24 +0000 | [diff] [blame] | 9922 | if ConditionPassed() then | 
|  | 9923 | EncodingSpecificOperations(); | 
|  | 9924 | offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | 9925 | address = if index then offset_addr else R[n]; | 
|  | 9926 | MemU[address,4] = if t == 15 then PCStoreValue() else R[t]; | 
|  | 9927 | if wback then R[n] = offset_addr; | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 9928 | #endif | 
|  | 9929 |  | 
| Caroline Tice | d42b3cc | 2011-03-30 06:03:24 +0000 | [diff] [blame] | 9930 | bool success = false; | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 9931 |  | 
|  | 9932 | if (ConditionPassed(opcode)) | 
|  | 9933 | { | 
| Caroline Tice | d42b3cc | 2011-03-30 06:03:24 +0000 | [diff] [blame] | 9934 | uint32_t t; | 
|  | 9935 | uint32_t n; | 
|  | 9936 | uint32_t imm32; | 
|  | 9937 | bool index; | 
|  | 9938 | bool add; | 
|  | 9939 | bool wback; | 
|  | 9940 |  | 
|  | 9941 | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  | 9942 |  | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 9943 | switch (encoding) | 
|  | 9944 | { | 
| Caroline Tice | d42b3cc | 2011-03-30 06:03:24 +0000 | [diff] [blame] | 9945 | case eEncodingA1: | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 9946 | // if P == Ô0Õ && W == Ô1Õ then SEE STRT; | 
|  | 9947 | // if Rn == Ô1101Õ && P == Ô1Õ && U == Ô0Õ && W == Ô1Õ && imm12 == Ô000000000100Õ then SEE PUSH; | 
| Caroline Tice | d42b3cc | 2011-03-30 06:03:24 +0000 | [diff] [blame] | 9948 | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32); | 
|  | 9949 | t = Bits32 (opcode, 15, 12); | 
|  | 9950 | n = Bits32 (opcode, 19, 16); | 
|  | 9951 | imm32 = Bits32 (opcode, 11, 0); | 
|  | 9952 |  | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 9953 | // index = (P == Ô1Õ); add = (U == Ô1Õ); wback = (P == Ô0Õ) || (W == Ô1Õ); | 
| Caroline Tice | d42b3cc | 2011-03-30 06:03:24 +0000 | [diff] [blame] | 9954 | index = BitIsSet (opcode, 24); | 
|  | 9955 | add = BitIsSet (opcode, 23); | 
|  | 9956 | wback = BitIsClear (opcode, 24) || BitIsSet (opcode, 21); | 
|  | 9957 |  | 
|  | 9958 | // if wback && (n == 15 || n == t) then UNPREDICTABLE; | 
|  | 9959 | if (wback && ((n == 15) || (n == t))) | 
|  | 9960 | return false; | 
|  | 9961 |  | 
|  | 9962 | break; | 
|  | 9963 |  | 
|  | 9964 | default: | 
|  | 9965 | return false; | 
|  | 9966 | } | 
|  | 9967 |  | 
|  | 9968 | // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | 9969 | uint32_t Rn = ReadCoreReg (n, &success); | 
|  | 9970 | if (!success) | 
|  | 9971 | return false; | 
|  | 9972 |  | 
|  | 9973 | addr_t offset_addr; | 
|  | 9974 | if (add) | 
|  | 9975 | offset_addr = Rn + imm32; | 
|  | 9976 | else | 
|  | 9977 | offset_addr = Rn - imm32; | 
|  | 9978 |  | 
|  | 9979 | // address = if index then offset_addr else R[n]; | 
|  | 9980 | addr_t address; | 
|  | 9981 | if (index) | 
|  | 9982 | address = offset_addr; | 
|  | 9983 | else | 
|  | 9984 | address = Rn; | 
|  | 9985 |  | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 9986 | RegisterInfo base_reg; | 
|  | 9987 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
|  | 9988 | RegisterInfo data_reg; | 
|  | 9989 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + t, data_reg); | 
| Caroline Tice | d42b3cc | 2011-03-30 06:03:24 +0000 | [diff] [blame] | 9990 | EmulateInstruction::Context context; | 
|  | 9991 | context.type = eContextRegisterStore; | 
|  | 9992 | context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, address - Rn); | 
|  | 9993 |  | 
|  | 9994 | // MemU[address,4] = if t == 15 then PCStoreValue() else R[t]; | 
|  | 9995 | uint32_t Rt = ReadCoreReg (t, &success); | 
|  | 9996 | if (!success) | 
|  | 9997 | return false; | 
|  | 9998 |  | 
|  | 9999 | if (t == 15) | 
|  | 10000 | { | 
| Caroline Tice | e98b958 | 2011-03-30 16:05:23 +0000 | [diff] [blame] | 10001 | uint32_t pc_value = ReadCoreReg (PC_REG, &success); | 
| Caroline Tice | d42b3cc | 2011-03-30 06:03:24 +0000 | [diff] [blame] | 10002 | if (!success) | 
|  | 10003 | return false; | 
|  | 10004 |  | 
|  | 10005 | if (!MemUWrite (context, address, pc_value, addr_byte_size)) | 
|  | 10006 | return false; | 
|  | 10007 | } | 
|  | 10008 | else | 
|  | 10009 | { | 
|  | 10010 | if (!MemUWrite (context, address, Rt, addr_byte_size)) | 
|  | 10011 | return false; | 
|  | 10012 | } | 
|  | 10013 |  | 
|  | 10014 | // if wback then R[n] = offset_addr; | 
|  | 10015 | if (wback) | 
|  | 10016 | { | 
|  | 10017 | context.type = eContextAdjustBaseRegister; | 
|  | 10018 | context.SetImmediate (offset_addr); | 
|  | 10019 |  | 
|  | 10020 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr)) | 
|  | 10021 | return false; | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 10022 | } | 
|  | 10023 | } | 
|  | 10024 | return true; | 
|  | 10025 | } | 
|  | 10026 |  | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 10027 | // A8.6.66 LDRD (immediate) | 
| Caroline Tice | 1697dd7 | 2011-03-30 17:11:45 +0000 | [diff] [blame] | 10028 | // Load Register Dual (immediate) calculates an address from a base register value and an immediate offset, loads two | 
|  | 10029 | // words from memory, and writes them to two registers.  It can use offset, post-indexed, or pre-indexed addressing. | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 10030 | bool | 
|  | 10031 | EmulateInstructionARM::EmulateLDRDImmediate (const uint32_t opcode, const ARMEncoding encoding) | 
|  | 10032 | { | 
|  | 10033 | #if 0 | 
| Caroline Tice | 1697dd7 | 2011-03-30 17:11:45 +0000 | [diff] [blame] | 10034 | if ConditionPassed() then | 
|  | 10035 | EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | 10036 | offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | 10037 | address = if index then offset_addr else R[n]; | 
|  | 10038 | R[t] = MemA[address,4]; | 
|  | 10039 | R[t2] = MemA[address+4,4]; | 
|  | 10040 | if wback then R[n] = offset_addr; | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 10041 | #endif | 
|  | 10042 |  | 
| Caroline Tice | 1697dd7 | 2011-03-30 17:11:45 +0000 | [diff] [blame] | 10043 | bool success = false; | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 10044 |  | 
|  | 10045 | if (ConditionPassed(opcode)) | 
|  | 10046 | { | 
| Caroline Tice | 1697dd7 | 2011-03-30 17:11:45 +0000 | [diff] [blame] | 10047 | uint32_t t; | 
|  | 10048 | uint32_t t2; | 
|  | 10049 | uint32_t n; | 
|  | 10050 | uint32_t imm32; | 
|  | 10051 | bool index; | 
|  | 10052 | bool add; | 
|  | 10053 | bool wback; | 
|  | 10054 |  | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 10055 | switch (encoding) | 
|  | 10056 | { | 
| Caroline Tice | 1697dd7 | 2011-03-30 17:11:45 +0000 | [diff] [blame] | 10057 | case eEncodingT1: | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 10058 | //if P == Ô0Õ && W == Ô0Õ then SEE ÒRelated encodingsÓ; | 
|  | 10059 | //if Rn == Ô1111Õ then SEE LDRD (literal); | 
|  | 10060 | //t = UInt(Rt); t2 = UInt(Rt2); n = UInt(Rn); imm32 = ZeroExtend(imm8:Õ00Õ, 32); | 
| Caroline Tice | 1697dd7 | 2011-03-30 17:11:45 +0000 | [diff] [blame] | 10061 | t = Bits32 (opcode, 15, 12); | 
|  | 10062 | t2 = Bits32 (opcode, 11, 8); | 
|  | 10063 | n = Bits32 (opcode, 19, 16); | 
|  | 10064 | imm32 = Bits32 (opcode, 7, 0) << 2; | 
|  | 10065 |  | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 10066 | //index = (P == Ô1Õ); add = (U == Ô1Õ); wback = (W == Ô1Õ); | 
| Caroline Tice | 1697dd7 | 2011-03-30 17:11:45 +0000 | [diff] [blame] | 10067 | index = BitIsSet (opcode, 24); | 
|  | 10068 | add = BitIsSet (opcode, 23); | 
|  | 10069 | wback = BitIsSet (opcode, 21); | 
|  | 10070 |  | 
|  | 10071 | //if wback && (n == t || n == t2) then UNPREDICTABLE; | 
|  | 10072 | if (wback && ((n == t) || (n == t2))) | 
|  | 10073 | return false; | 
|  | 10074 |  | 
|  | 10075 | //if BadReg(t) || BadReg(t2) || t == t2 then UNPREDICTABLE; | 
|  | 10076 | if (BadReg (t) || BadReg (t2) || (t == t2)) | 
|  | 10077 | return false; | 
|  | 10078 |  | 
|  | 10079 | break; | 
|  | 10080 |  | 
|  | 10081 | case eEncodingA1: | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 10082 | //if Rn == Ô1111Õ then SEE LDRD (literal); | 
|  | 10083 | //if Rt<0> == Ô1Õ then UNPREDICTABLE; | 
| Caroline Tice | 1697dd7 | 2011-03-30 17:11:45 +0000 | [diff] [blame] | 10084 | //t = UInt(Rt); t2 = t+1; n = UInt(Rn); imm32 = ZeroExtend(imm4H:imm4L, 32); | 
|  | 10085 | t = Bits32 (opcode, 15, 12); | 
| Caroline Tice | eab301f | 2011-03-30 17:54:52 +0000 | [diff] [blame] | 10086 | if (BitIsSet (t, 0)) | 
|  | 10087 | return false; | 
| Caroline Tice | 1697dd7 | 2011-03-30 17:11:45 +0000 | [diff] [blame] | 10088 | t2 = t + 1; | 
|  | 10089 | n = Bits32 (opcode, 19, 16); | 
|  | 10090 | imm32 = (Bits32 (opcode, 11, 8) << 4) | Bits32 (opcode, 3, 0); | 
|  | 10091 |  | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 10092 | //index = (P == Ô1Õ); add = (U == Ô1Õ); wback = (P == Ô0Õ) || (W == Ô1Õ); | 
| Caroline Tice | 1697dd7 | 2011-03-30 17:11:45 +0000 | [diff] [blame] | 10093 | index = BitIsSet (opcode, 24); | 
|  | 10094 | add = BitIsSet (opcode, 23); | 
|  | 10095 | wback = BitIsClear (opcode, 24) || BitIsSet (opcode, 21); | 
|  | 10096 |  | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 10097 | //if P == Ô0Õ && W == Ô1Õ then UNPREDICTABLE; | 
| Caroline Tice | 1697dd7 | 2011-03-30 17:11:45 +0000 | [diff] [blame] | 10098 | if (BitIsClear (opcode, 24) && BitIsSet (opcode, 21)) | 
|  | 10099 | return false; | 
|  | 10100 |  | 
|  | 10101 | //if wback && (n == t || n == t2) then UNPREDICTABLE; | 
|  | 10102 | if (wback && ((n == t) || (n == t2))) | 
|  | 10103 | return false; | 
|  | 10104 |  | 
|  | 10105 | //if t2 == 15 then UNPREDICTABLE; | 
|  | 10106 | if (t2 == 15) | 
|  | 10107 | return false; | 
|  | 10108 |  | 
|  | 10109 | break; | 
|  | 10110 |  | 
|  | 10111 | default: | 
|  | 10112 | return false; | 
|  | 10113 | } | 
|  | 10114 |  | 
|  | 10115 | //offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | 10116 | uint32_t Rn = ReadCoreReg (n, &success); | 
|  | 10117 | if (!success) | 
|  | 10118 | return false; | 
|  | 10119 |  | 
|  | 10120 | addr_t offset_addr; | 
|  | 10121 | if (add) | 
|  | 10122 | offset_addr = Rn + imm32; | 
|  | 10123 | else | 
|  | 10124 | offset_addr = Rn - imm32; | 
|  | 10125 |  | 
|  | 10126 | //address = if index then offset_addr else R[n]; | 
|  | 10127 | addr_t address; | 
|  | 10128 | if (index) | 
|  | 10129 | address = offset_addr; | 
|  | 10130 | else | 
|  | 10131 | address = Rn; | 
|  | 10132 |  | 
|  | 10133 | //R[t] = MemA[address,4]; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 10134 | RegisterInfo base_reg; | 
|  | 10135 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
| Caroline Tice | 1697dd7 | 2011-03-30 17:11:45 +0000 | [diff] [blame] | 10136 |  | 
|  | 10137 | EmulateInstruction::Context context; | 
|  | 10138 | context.type = eContextRegisterLoad; | 
|  | 10139 | context.SetRegisterPlusOffset (base_reg, address - Rn); | 
|  | 10140 |  | 
|  | 10141 | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  | 10142 | uint32_t data = MemARead (context, address, addr_byte_size, 0, &success); | 
|  | 10143 | if (!success) | 
|  | 10144 | return false; | 
|  | 10145 |  | 
|  | 10146 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, data)) | 
|  | 10147 | return false; | 
|  | 10148 |  | 
|  | 10149 | //R[t2] = MemA[address+4,4]; | 
|  | 10150 |  | 
|  | 10151 | context.SetRegisterPlusOffset (base_reg, (address + 4) - Rn); | 
|  | 10152 | data = MemARead (context, address + 4, addr_byte_size, 0, &success); | 
|  | 10153 | if (!success) | 
|  | 10154 | return false; | 
|  | 10155 |  | 
|  | 10156 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t2, data)) | 
|  | 10157 | return false; | 
|  | 10158 |  | 
|  | 10159 | //if wback then R[n] = offset_addr; | 
|  | 10160 | if (wback) | 
|  | 10161 | { | 
|  | 10162 | context.type = eContextAdjustBaseRegister; | 
|  | 10163 | context.SetAddress (offset_addr); | 
|  | 10164 |  | 
|  | 10165 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr)) | 
|  | 10166 | return false; | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 10167 | } | 
|  | 10168 | } | 
|  | 10169 | return true; | 
|  | 10170 | } | 
|  | 10171 |  | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 10172 | // A8.6.68 LDRD (register) | 
| Caroline Tice | eab301f | 2011-03-30 17:54:52 +0000 | [diff] [blame] | 10173 | // Load Register Dual (register) calculates an address from a base register value and a register offset, loads two | 
|  | 10174 | // words from memory, and writes them to two registers.  It can use offset, post-indexed or pre-indexed addressing. | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 10175 | bool | 
|  | 10176 | EmulateInstructionARM::EmulateLDRDRegister (const uint32_t opcode, const ARMEncoding encoding) | 
|  | 10177 | { | 
|  | 10178 | #if 0 | 
| Caroline Tice | eab301f | 2011-03-30 17:54:52 +0000 | [diff] [blame] | 10179 | if ConditionPassed() then | 
|  | 10180 | EncodingSpecificOperations(); | 
|  | 10181 | offset_addr = if add then (R[n] + R[m]) else (R[n] - R[m]); | 
|  | 10182 | address = if index then offset_addr else R[n]; | 
|  | 10183 | R[t] = MemA[address,4]; | 
|  | 10184 | R[t2] = MemA[address+4,4]; | 
|  | 10185 | if wback then R[n] = offset_addr; | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 10186 | #endif | 
|  | 10187 |  | 
| Caroline Tice | eab301f | 2011-03-30 17:54:52 +0000 | [diff] [blame] | 10188 | bool success = false; | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 10189 |  | 
|  | 10190 | if (ConditionPassed(opcode)) | 
|  | 10191 | { | 
| Caroline Tice | eab301f | 2011-03-30 17:54:52 +0000 | [diff] [blame] | 10192 | uint32_t t; | 
|  | 10193 | uint32_t t2; | 
|  | 10194 | uint32_t n; | 
|  | 10195 | uint32_t m; | 
|  | 10196 | bool index; | 
|  | 10197 | bool add; | 
|  | 10198 | bool wback; | 
|  | 10199 |  | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 10200 | switch (encoding) | 
|  | 10201 | { | 
| Caroline Tice | eab301f | 2011-03-30 17:54:52 +0000 | [diff] [blame] | 10202 | case eEncodingA1: | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 10203 | // if Rt<0> == Ô1Õ then UNPREDICTABLE; | 
| Caroline Tice | eab301f | 2011-03-30 17:54:52 +0000 | [diff] [blame] | 10204 | // t = UInt(Rt); t2 = t+1; n = UInt(Rn); m = UInt(Rm); | 
|  | 10205 | t = Bits32 (opcode, 15, 12); | 
|  | 10206 | if (BitIsSet (t, 0)) | 
|  | 10207 | return false; | 
|  | 10208 | t2 = t + 1; | 
|  | 10209 | n = Bits32 (opcode, 19, 16); | 
|  | 10210 | m = Bits32 (opcode, 3, 0); | 
|  | 10211 |  | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 10212 | // index = (P == Ô1Õ); add = (U == Ô1Õ); wback = (P == Ô0Õ) || (W == Ô1Õ); | 
| Caroline Tice | eab301f | 2011-03-30 17:54:52 +0000 | [diff] [blame] | 10213 | index = BitIsSet (opcode, 24); | 
|  | 10214 | add = BitIsSet (opcode, 23); | 
|  | 10215 | wback = BitIsClear (opcode, 24) || BitIsSet (opcode, 21); | 
|  | 10216 |  | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 10217 | // if P == Ô0Õ && W == Ô1Õ then UNPREDICTABLE; | 
| Caroline Tice | eab301f | 2011-03-30 17:54:52 +0000 | [diff] [blame] | 10218 | if (BitIsClear (opcode, 24) && BitIsSet (opcode, 21)) | 
|  | 10219 | return false; | 
|  | 10220 |  | 
|  | 10221 | // if t2 == 15 || m == 15 || m == t || m == t2 then UNPREDICTABLE; | 
|  | 10222 | if ((t2 == 15) || (m == 15) || (m == t) || (m == t2)) | 
|  | 10223 | return false; | 
|  | 10224 |  | 
|  | 10225 | // if wback && (n == 15 || n == t || n == t2) then UNPREDICTABLE; | 
|  | 10226 | if (wback && ((n == 15) || (n == t) || (n == t2))) | 
|  | 10227 | return false; | 
|  | 10228 |  | 
|  | 10229 | // if ArchVersion() < 6 && wback && m == n then UNPREDICTABLE; | 
|  | 10230 | if ((ArchVersion() < 6) && wback && (m == n)) | 
|  | 10231 | return false; | 
|  | 10232 | break; | 
|  | 10233 |  | 
|  | 10234 | default: | 
|  | 10235 | return false; | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 10236 | } | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 10237 |  | 
| Caroline Tice | eab301f | 2011-03-30 17:54:52 +0000 | [diff] [blame] | 10238 | uint32_t Rn = ReadCoreReg (n, &success); | 
|  | 10239 | if (!success) | 
|  | 10240 | return false; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 10241 | RegisterInfo base_reg; | 
|  | 10242 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 10243 |  | 
| Caroline Tice | eab301f | 2011-03-30 17:54:52 +0000 | [diff] [blame] | 10244 | uint32_t Rm = ReadCoreReg (m, &success); | 
|  | 10245 | if (!success) | 
|  | 10246 | return false; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 10247 | RegisterInfo offset_reg; | 
|  | 10248 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + m, offset_reg); | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 10249 |  | 
| Caroline Tice | eab301f | 2011-03-30 17:54:52 +0000 | [diff] [blame] | 10250 | // offset_addr = if add then (R[n] + R[m]) else (R[n] - R[m]); | 
|  | 10251 | addr_t offset_addr; | 
|  | 10252 | if (add) | 
|  | 10253 | offset_addr = Rn + Rm; | 
|  | 10254 | else | 
|  | 10255 | offset_addr = Rn - Rm; | 
|  | 10256 |  | 
|  | 10257 | // address = if index then offset_addr else R[n]; | 
|  | 10258 | addr_t address; | 
|  | 10259 | if (index) | 
|  | 10260 | address = offset_addr; | 
|  | 10261 | else | 
|  | 10262 | address = Rn; | 
|  | 10263 |  | 
|  | 10264 | EmulateInstruction::Context context; | 
|  | 10265 | context.type = eContextRegisterLoad; | 
|  | 10266 | context.SetRegisterPlusIndirectOffset (base_reg, offset_reg); | 
|  | 10267 |  | 
|  | 10268 | // R[t] = MemA[address,4]; | 
|  | 10269 | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  | 10270 | uint32_t data = MemARead (context, address, addr_byte_size, 0, &success); | 
|  | 10271 | if (!success) | 
|  | 10272 | return false; | 
|  | 10273 |  | 
|  | 10274 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, data)) | 
|  | 10275 | return false; | 
|  | 10276 |  | 
|  | 10277 | // R[t2] = MemA[address+4,4]; | 
|  | 10278 |  | 
|  | 10279 | data = MemARead (context, address + 4, addr_byte_size, 0, &success); | 
|  | 10280 | if (!success) | 
|  | 10281 | return false; | 
|  | 10282 |  | 
|  | 10283 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t2, data)) | 
|  | 10284 | return false; | 
|  | 10285 |  | 
|  | 10286 | // if wback then R[n] = offset_addr; | 
|  | 10287 | if (wback) | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 10288 | { | 
| Caroline Tice | eab301f | 2011-03-30 17:54:52 +0000 | [diff] [blame] | 10289 | context.type = eContextAdjustBaseRegister; | 
|  | 10290 | context.SetAddress (offset_addr); | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 10291 |  | 
| Caroline Tice | eab301f | 2011-03-30 17:54:52 +0000 | [diff] [blame] | 10292 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr)) | 
|  | 10293 | return false; | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 10294 | } | 
|  | 10295 | } | 
|  | 10296 | return true; | 
|  | 10297 | } | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 10298 |  | 
|  | 10299 | // A8.6.200 STRD (immediate) | 
| Caroline Tice | 74467fe | 2011-03-30 19:02:56 +0000 | [diff] [blame] | 10300 | // Store Register Dual (immediate) calculates an address from a base register value and an immediate offset, and | 
|  | 10301 | // stores two words from two registers to memory.  It can use offset, post-indexed, or pre-indexed addressing. | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 10302 | bool | 
|  | 10303 | EmulateInstructionARM::EmulateSTRDImm (const uint32_t opcode, const ARMEncoding encoding) | 
|  | 10304 | { | 
|  | 10305 | #if 0 | 
| Caroline Tice | 74467fe | 2011-03-30 19:02:56 +0000 | [diff] [blame] | 10306 | if ConditionPassed() then | 
|  | 10307 | EncodingSpecificOperations(); NullCheckIfThumbEE(n); | 
|  | 10308 | offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | 10309 | address = if index then offset_addr else R[n]; | 
|  | 10310 | MemA[address,4] = R[t]; | 
|  | 10311 | MemA[address+4,4] = R[t2]; | 
|  | 10312 | if wback then R[n] = offset_addr; | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 10313 | #endif | 
|  | 10314 |  | 
| Caroline Tice | 74467fe | 2011-03-30 19:02:56 +0000 | [diff] [blame] | 10315 | bool success = false; | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 10316 |  | 
| Caroline Tice | 74467fe | 2011-03-30 19:02:56 +0000 | [diff] [blame] | 10317 | if (ConditionPassed(opcode)) | 
|  | 10318 | { | 
|  | 10319 | uint32_t t; | 
|  | 10320 | uint32_t t2; | 
|  | 10321 | uint32_t n; | 
|  | 10322 | uint32_t imm32; | 
|  | 10323 | bool index; | 
|  | 10324 | bool add; | 
|  | 10325 | bool wback; | 
|  | 10326 |  | 
|  | 10327 | switch (encoding) | 
|  | 10328 | { | 
|  | 10329 | case eEncodingT1: | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 10330 | // if P == Ô0Õ && W == Ô0Õ then SEE ÒRelated encodingsÓ; | 
|  | 10331 | // t = UInt(Rt); t2 = UInt(Rt2); n = UInt(Rn); imm32 = ZeroExtend(imm8:Õ00Õ, 32); | 
| Caroline Tice | 74467fe | 2011-03-30 19:02:56 +0000 | [diff] [blame] | 10332 | t = Bits32 (opcode, 15, 12); | 
|  | 10333 | t2 = Bits32 (opcode, 11, 8); | 
|  | 10334 | n = Bits32 (opcode, 19, 16); | 
|  | 10335 | imm32 = Bits32 (opcode, 7, 0) << 2; | 
|  | 10336 |  | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 10337 | // index = (P == Ô1Õ); add = (U == Ô1Õ); wback = (W == Ô1Õ); | 
| Caroline Tice | 74467fe | 2011-03-30 19:02:56 +0000 | [diff] [blame] | 10338 | index = BitIsSet (opcode, 24); | 
|  | 10339 | add = BitIsSet (opcode, 23); | 
|  | 10340 | wback = BitIsSet (opcode, 21); | 
|  | 10341 |  | 
|  | 10342 | // if wback && (n == t || n == t2) then UNPREDICTABLE; | 
|  | 10343 | if (wback && ((n == t) || (n == t2))) | 
|  | 10344 | return false; | 
|  | 10345 |  | 
|  | 10346 | // if n == 15 || BadReg(t) || BadReg(t2) then UNPREDICTABLE; | 
|  | 10347 | if ((n == 15) || BadReg (t) || BadReg (t2)) | 
|  | 10348 | return false; | 
|  | 10349 |  | 
|  | 10350 | break; | 
|  | 10351 |  | 
|  | 10352 | case eEncodingA1: | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 10353 | // if Rt<0> == Ô1Õ then UNPREDICTABLE; | 
| Caroline Tice | 74467fe | 2011-03-30 19:02:56 +0000 | [diff] [blame] | 10354 | // t = UInt(Rt); t2 = t+1; n = UInt(Rn); imm32 = ZeroExtend(imm4H:imm4L, 32); | 
|  | 10355 | t = Bits32 (opcode, 15, 12); | 
|  | 10356 | if (BitIsSet (t, 0)) | 
|  | 10357 | return false; | 
|  | 10358 |  | 
|  | 10359 | t2 = t + 1; | 
|  | 10360 | n = Bits32 (opcode, 19, 16); | 
|  | 10361 | imm32 = (Bits32 (opcode, 11, 8) << 4) | Bits32 (opcode, 3, 0); | 
|  | 10362 |  | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 10363 | // index = (P == Ô1Õ); add = (U == Ô1Õ); wback = (P == Ô0Õ) || (W == Ô1Õ); | 
| Caroline Tice | 74467fe | 2011-03-30 19:02:56 +0000 | [diff] [blame] | 10364 | index = BitIsSet (opcode, 24); | 
|  | 10365 | add = BitIsSet (opcode, 23); | 
|  | 10366 | wback = BitIsClear (opcode, 24) || BitIsSet (opcode, 21); | 
|  | 10367 |  | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 10368 | // if P == Ô0Õ && W == Ô1Õ then UNPREDICTABLE; | 
| Caroline Tice | 74467fe | 2011-03-30 19:02:56 +0000 | [diff] [blame] | 10369 | if (BitIsClear (opcode, 24) && BitIsSet (opcode, 21)) | 
|  | 10370 | return false; | 
|  | 10371 |  | 
|  | 10372 | // if wback && (n == 15 || n == t || n == t2) then UNPREDICTABLE; | 
|  | 10373 | if (wback && ((n == 15) || (n == t) || (n == t2))) | 
|  | 10374 | return false; | 
|  | 10375 |  | 
|  | 10376 | // if t2 == 15 then UNPREDICTABLE; | 
|  | 10377 | if (t2 == 15) | 
|  | 10378 | return false; | 
|  | 10379 |  | 
|  | 10380 | break; | 
|  | 10381 |  | 
|  | 10382 | default: | 
|  | 10383 | return false; | 
|  | 10384 | } | 
|  | 10385 |  | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 10386 | RegisterInfo base_reg; | 
|  | 10387 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
| Caroline Tice | 74467fe | 2011-03-30 19:02:56 +0000 | [diff] [blame] | 10388 |  | 
|  | 10389 | uint32_t Rn = ReadCoreReg (n, &success); | 
|  | 10390 | if (!success) | 
|  | 10391 | return false; | 
|  | 10392 |  | 
|  | 10393 | //offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | 10394 | addr_t offset_addr; | 
|  | 10395 | if (add) | 
|  | 10396 | offset_addr = Rn + imm32; | 
|  | 10397 | else | 
|  | 10398 | offset_addr = Rn - imm32; | 
|  | 10399 |  | 
|  | 10400 | //address = if index then offset_addr else R[n]; | 
|  | 10401 | addr_t address; | 
|  | 10402 | if (index) | 
|  | 10403 | address = offset_addr; | 
|  | 10404 | else | 
|  | 10405 | address = Rn; | 
|  | 10406 |  | 
|  | 10407 | //MemA[address,4] = R[t]; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 10408 | RegisterInfo data_reg; | 
|  | 10409 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + t, data_reg); | 
| Caroline Tice | 74467fe | 2011-03-30 19:02:56 +0000 | [diff] [blame] | 10410 |  | 
|  | 10411 | uint32_t data = ReadCoreReg (t, &success); | 
|  | 10412 | if (!success) | 
|  | 10413 | return false; | 
|  | 10414 |  | 
|  | 10415 | EmulateInstruction::Context context; | 
|  | 10416 | context.type = eContextRegisterStore; | 
|  | 10417 | context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, address - Rn); | 
|  | 10418 |  | 
|  | 10419 | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  | 10420 |  | 
|  | 10421 | if (!MemAWrite (context, address, data, addr_byte_size)) | 
|  | 10422 | return false; | 
|  | 10423 |  | 
|  | 10424 | //MemA[address+4,4] = R[t2]; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 10425 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + t2, data_reg); | 
| Caroline Tice | 74467fe | 2011-03-30 19:02:56 +0000 | [diff] [blame] | 10426 | context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, (address + 4) - Rn); | 
|  | 10427 |  | 
|  | 10428 | data = ReadCoreReg (t2, &success); | 
|  | 10429 | if (!success) | 
|  | 10430 | return false; | 
|  | 10431 |  | 
|  | 10432 | if (!MemAWrite (context, address + 4, data, addr_byte_size)) | 
|  | 10433 | return false; | 
|  | 10434 |  | 
|  | 10435 | //if wback then R[n] = offset_addr; | 
|  | 10436 | if (wback) | 
|  | 10437 | { | 
|  | 10438 | context.type = eContextAdjustBaseRegister; | 
|  | 10439 | context.SetAddress (offset_addr); | 
|  | 10440 |  | 
|  | 10441 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr)) | 
|  | 10442 | return false; | 
|  | 10443 | } | 
|  | 10444 | } | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 10445 | return true; | 
|  | 10446 | } | 
|  | 10447 |  | 
|  | 10448 |  | 
|  | 10449 | // A8.6.201 STRD (register) | 
|  | 10450 | bool | 
|  | 10451 | EmulateInstructionARM::EmulateSTRDReg (const uint32_t opcode, const ARMEncoding encoding) | 
|  | 10452 | { | 
|  | 10453 | #if 0 | 
| Caroline Tice | 74467fe | 2011-03-30 19:02:56 +0000 | [diff] [blame] | 10454 | if ConditionPassed() then | 
|  | 10455 | EncodingSpecificOperations(); | 
|  | 10456 | offset_addr = if add then (R[n] + R[m]) else (R[n] - R[m]); | 
|  | 10457 | address = if index then offset_addr else R[n]; | 
|  | 10458 | MemA[address,4] = R[t]; | 
|  | 10459 | MemA[address+4,4] = R[t2]; | 
|  | 10460 | if wback then R[n] = offset_addr; | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 10461 | #endif | 
|  | 10462 |  | 
| Caroline Tice | 74467fe | 2011-03-30 19:02:56 +0000 | [diff] [blame] | 10463 | bool success = false; | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 10464 |  | 
| Caroline Tice | 74467fe | 2011-03-30 19:02:56 +0000 | [diff] [blame] | 10465 | if (ConditionPassed(opcode)) | 
|  | 10466 | { | 
|  | 10467 | uint32_t t; | 
|  | 10468 | uint32_t t2; | 
|  | 10469 | uint32_t n; | 
|  | 10470 | uint32_t m; | 
|  | 10471 | bool index; | 
|  | 10472 | bool add; | 
|  | 10473 | bool wback; | 
|  | 10474 |  | 
|  | 10475 | switch (encoding) | 
|  | 10476 | { | 
|  | 10477 | case eEncodingA1: | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 10478 | // if Rt<0> == Ô1Õ then UNPREDICTABLE; | 
| Caroline Tice | 74467fe | 2011-03-30 19:02:56 +0000 | [diff] [blame] | 10479 | // t = UInt(Rt); t2 = t+1; n = UInt(Rn); m = UInt(Rm); | 
|  | 10480 | t = Bits32 (opcode, 15, 12); | 
|  | 10481 | if (BitIsSet (t, 0)) | 
|  | 10482 | return false; | 
|  | 10483 |  | 
|  | 10484 | t2 = t+1; | 
|  | 10485 | n = Bits32 (opcode, 19, 16); | 
|  | 10486 | m = Bits32 (opcode, 3, 0); | 
|  | 10487 |  | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 10488 | // index = (P == Ô1Õ); add = (U == Ô1Õ); wback = (P == Ô0Õ) || (W == Ô1Õ); | 
| Caroline Tice | 74467fe | 2011-03-30 19:02:56 +0000 | [diff] [blame] | 10489 | index = BitIsSet (opcode, 24); | 
|  | 10490 | add = BitIsSet (opcode, 23); | 
|  | 10491 | wback = BitIsClear (opcode, 24) || BitIsSet (opcode, 21); | 
|  | 10492 |  | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 10493 | // if P == Ô0Õ && W == Ô1Õ then UNPREDICTABLE; | 
| Caroline Tice | 74467fe | 2011-03-30 19:02:56 +0000 | [diff] [blame] | 10494 | if (BitIsClear (opcode, 24) && BitIsSet (opcode, 21)) | 
|  | 10495 | return false; | 
|  | 10496 |  | 
|  | 10497 | // if t2 == 15 || m == 15 then UNPREDICTABLE; | 
|  | 10498 | if ((t2 == 15) || (m == 15)) | 
|  | 10499 | return false; | 
|  | 10500 |  | 
|  | 10501 | // if wback && (n == 15 || n == t || n == t2) then UNPREDICTABLE; | 
|  | 10502 | if (wback && ((n == 15) || (n == t) || (n == t2))) | 
|  | 10503 | return false; | 
|  | 10504 |  | 
|  | 10505 | // if ArchVersion() < 6 && wback && m == n then UNPREDICTABLE; | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 10506 | if ((ArchVersion() < 6) && wback && (m == n)) | 
| Caroline Tice | 74467fe | 2011-03-30 19:02:56 +0000 | [diff] [blame] | 10507 | return false; | 
|  | 10508 |  | 
|  | 10509 | break; | 
|  | 10510 |  | 
|  | 10511 | default: | 
|  | 10512 | return false; | 
|  | 10513 | } | 
|  | 10514 |  | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 10515 | RegisterInfo base_reg; | 
|  | 10516 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
|  | 10517 | RegisterInfo offset_reg; | 
|  | 10518 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + m, offset_reg); | 
|  | 10519 | RegisterInfo data_reg; | 
| Caroline Tice | 74467fe | 2011-03-30 19:02:56 +0000 | [diff] [blame] | 10520 |  | 
|  | 10521 | uint32_t Rn = ReadCoreReg (n, &success); | 
|  | 10522 | if (!success) | 
|  | 10523 | return false; | 
|  | 10524 |  | 
|  | 10525 | uint32_t Rm = ReadCoreReg (m, &success); | 
|  | 10526 | if (!success) | 
|  | 10527 | return false; | 
|  | 10528 |  | 
|  | 10529 | // offset_addr = if add then (R[n] + R[m]) else (R[n] - R[m]); | 
|  | 10530 | addr_t offset_addr; | 
|  | 10531 | if (add) | 
|  | 10532 | offset_addr = Rn + Rm; | 
|  | 10533 | else | 
|  | 10534 | offset_addr = Rn - Rm; | 
|  | 10535 |  | 
|  | 10536 | // address = if index then offset_addr else R[n]; | 
|  | 10537 | addr_t address; | 
|  | 10538 | if (index) | 
|  | 10539 | address = offset_addr; | 
|  | 10540 | else | 
|  | 10541 | address = Rn; | 
|  | 10542 | // MemA[address,4] = R[t]; | 
|  | 10543 | uint32_t Rt = ReadCoreReg (t, &success); | 
|  | 10544 | if (!success) | 
|  | 10545 | return false; | 
|  | 10546 |  | 
|  | 10547 | EmulateInstruction::Context context; | 
|  | 10548 | context.type = eContextRegisterStore; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 10549 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + t, data_reg); | 
| Caroline Tice | 74467fe | 2011-03-30 19:02:56 +0000 | [diff] [blame] | 10550 | context.SetRegisterToRegisterPlusIndirectOffset (base_reg, offset_reg, data_reg); | 
|  | 10551 |  | 
|  | 10552 | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  | 10553 |  | 
|  | 10554 | if (!MemAWrite (context, address, Rt, addr_byte_size)) | 
|  | 10555 | return false; | 
|  | 10556 |  | 
|  | 10557 | // MemA[address+4,4] = R[t2]; | 
|  | 10558 | uint32_t Rt2 = ReadCoreReg (t2, &success); | 
|  | 10559 | if (!success) | 
|  | 10560 | return false; | 
|  | 10561 |  | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 10562 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + t2, data_reg); | 
| Caroline Tice | 74467fe | 2011-03-30 19:02:56 +0000 | [diff] [blame] | 10563 |  | 
|  | 10564 | context.SetRegisterToRegisterPlusIndirectOffset (base_reg, offset_reg, data_reg); | 
|  | 10565 |  | 
|  | 10566 | if (!MemAWrite (context, address + 4, Rt2, addr_byte_size)) | 
|  | 10567 | return false; | 
|  | 10568 |  | 
|  | 10569 | // if wback then R[n] = offset_addr; | 
|  | 10570 | if (wback) | 
|  | 10571 | { | 
|  | 10572 | context.type = eContextAdjustBaseRegister; | 
|  | 10573 | context.SetAddress (offset_addr); | 
|  | 10574 |  | 
|  | 10575 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr)) | 
|  | 10576 | return false; | 
|  | 10577 |  | 
|  | 10578 | } | 
|  | 10579 | } | 
| Greg Clayton | 24bc5d9 | 2011-03-30 18:16:51 +0000 | [diff] [blame] | 10580 | return true; | 
| Caroline Tice | d05b490 | 2011-03-29 21:24:06 +0000 | [diff] [blame] | 10581 | } | 
|  | 10582 |  | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 10583 | // A8.6.319 VLDM | 
|  | 10584 | // Vector Load Multiple loads multiple extension registers from consecutive memory locations using an address from | 
|  | 10585 | // an ARM core register. | 
|  | 10586 | bool | 
|  | 10587 | EmulateInstructionARM::EmulateVLDM (const uint32_t opcode, const ARMEncoding encoding) | 
|  | 10588 | { | 
|  | 10589 | #if 0 | 
|  | 10590 | if ConditionPassed() then | 
|  | 10591 | EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(n); | 
|  | 10592 | address = if add then R[n] else R[n]-imm32; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 10593 | if wback then R[n] = if add then R[n]+imm32 else R[n]-imm32; | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 10594 | for r = 0 to regs-1 | 
|  | 10595 | if single_regs then | 
|  | 10596 | S[d+r] = MemA[address,4]; address = address+4; | 
|  | 10597 | else | 
|  | 10598 | word1 = MemA[address,4]; word2 = MemA[address+4,4]; address = address+8; | 
|  | 10599 | // Combine the word-aligned words in the correct order for current endianness. | 
|  | 10600 | D[d+r] = if BigEndian() then word1:word2 else word2:word1; | 
|  | 10601 | #endif | 
|  | 10602 |  | 
|  | 10603 | bool success = false; | 
|  | 10604 |  | 
|  | 10605 | if (ConditionPassed(opcode)) | 
|  | 10606 | { | 
| Caroline Tice | bf5a66b | 2011-03-31 03:26:23 +0000 | [diff] [blame] | 10607 | bool single_regs; | 
|  | 10608 | bool add; | 
|  | 10609 | bool wback; | 
|  | 10610 | uint32_t d; | 
|  | 10611 | uint32_t n; | 
|  | 10612 | uint32_t imm32; | 
|  | 10613 | uint32_t regs; | 
|  | 10614 |  | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 10615 | switch (encoding) | 
|  | 10616 | { | 
|  | 10617 | case eEncodingT1: | 
|  | 10618 | case eEncodingA1: | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 10619 | // if P == Ô0Õ && U == Ô0Õ && W == Ô0Õ then SEE ÒRelated encodingsÓ; | 
|  | 10620 | // if P == Ô0Õ && U == Ô1Õ && W == Ô1Õ && Rn == Ô1101Õ then SEE VPOP; | 
|  | 10621 | // if P == Ô1Õ && W == Ô0Õ then SEE VLDR; | 
|  | 10622 | // if P == U && W == Ô1Õ then UNDEFINED; | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 10623 | if ((Bit32 (opcode, 24) == Bit32 (opcode, 23)) && BitIsSet (opcode, 21)) | 
|  | 10624 | return false; | 
|  | 10625 |  | 
|  | 10626 | // // Remaining combinations are PUW = 010 (IA without !), 011 (IA with !), 101 (DB with !) | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 10627 | // single_regs = FALSE; add = (U == Ô1Õ); wback = (W == Ô1Õ); | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 10628 | single_regs = false; | 
|  | 10629 | add = BitIsSet (opcode, 23); | 
|  | 10630 | wback = BitIsSet (opcode, 21); | 
|  | 10631 |  | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 10632 | // d = UInt(D:Vd); n = UInt(Rn); imm32 = ZeroExtend(imm8:Õ00Õ, 32); | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 10633 | d = (Bit32 (opcode, 22) << 4) | Bits32 (opcode, 15, 12); | 
|  | 10634 | n = Bits32 (opcode, 19, 16); | 
|  | 10635 | imm32 = Bits32 (opcode, 7, 0) << 2; | 
|  | 10636 |  | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 10637 | // regs = UInt(imm8) DIV 2; // If UInt(imm8) is odd, see ÒFLDMXÓ. | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 10638 | regs = Bits32 (opcode, 7, 0) / 2; | 
|  | 10639 |  | 
|  | 10640 | // if n == 15 && (wback || CurrentInstrSet() != InstrSet_ARM) then UNPREDICTABLE; | 
|  | 10641 | if (n == 15 && (wback || CurrentInstrSet() != eModeARM)) | 
|  | 10642 | return false; | 
|  | 10643 |  | 
|  | 10644 | // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE; | 
|  | 10645 | if ((regs == 0) || (regs > 16) || ((d + regs) > 32)) | 
|  | 10646 | return false; | 
|  | 10647 |  | 
|  | 10648 | break; | 
|  | 10649 |  | 
|  | 10650 | case eEncodingT2: | 
|  | 10651 | case eEncodingA2: | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 10652 | // if P == Ô0Õ && U == Ô0Õ && W == Ô0Õ then SEE ÒRelated encodingsÓ; | 
|  | 10653 | // if P == Ô0Õ && U == Ô1Õ && W == Ô1Õ && Rn == Ô1101Õ then SEE VPOP; | 
|  | 10654 | // if P == Ô1Õ && W == Ô0Õ then SEE VLDR; | 
|  | 10655 | // if P == U && W == Ô1Õ then UNDEFINED; | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 10656 | if ((Bit32 (opcode, 24) == Bit32 (opcode, 23)) && BitIsSet (opcode, 21)) | 
|  | 10657 | return false; | 
|  | 10658 |  | 
|  | 10659 | // // Remaining combinations are PUW = 010 (IA without !), 011 (IA with !), 101 (DB with !) | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 10660 | // single_regs = TRUE; add = (U == Ô1Õ); wback = (W == Ô1Õ); d = UInt(Vd:D); n = UInt(Rn); | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 10661 | single_regs = true; | 
|  | 10662 | add = BitIsSet (opcode, 23); | 
|  | 10663 | wback = BitIsSet (opcode, 21); | 
|  | 10664 | d = (Bits32 (opcode, 15, 12) << 1) | Bit32 (opcode, 22); | 
|  | 10665 | n = Bits32 (opcode, 19, 16); | 
|  | 10666 |  | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 10667 | // imm32 = ZeroExtend(imm8:Õ00Õ, 32); regs = UInt(imm8); | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 10668 | imm32 = Bits32 (opcode, 7, 0) << 2; | 
|  | 10669 | regs = Bits32 (opcode, 7, 0); | 
|  | 10670 |  | 
|  | 10671 | // if n == 15 && (wback || CurrentInstrSet() != InstrSet_ARM) then UNPREDICTABLE; | 
|  | 10672 | if ((n == 15) && (wback || (CurrentInstrSet() != eModeARM))) | 
|  | 10673 | return false; | 
|  | 10674 |  | 
|  | 10675 | // if regs == 0 || (d+regs) > 32 then UNPREDICTABLE; | 
|  | 10676 | if ((regs == 0) || ((d + regs) > 32)) | 
|  | 10677 | return false; | 
|  | 10678 | break; | 
|  | 10679 |  | 
|  | 10680 | default: | 
|  | 10681 | return false; | 
|  | 10682 | } | 
|  | 10683 |  | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 10684 | RegisterInfo base_reg; | 
|  | 10685 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 10686 |  | 
|  | 10687 | uint32_t Rn = ReadCoreReg (n, &success); | 
|  | 10688 | if (!success) | 
|  | 10689 | return false; | 
|  | 10690 |  | 
|  | 10691 | // address = if add then R[n] else R[n]-imm32; | 
|  | 10692 | addr_t address; | 
|  | 10693 | if (add) | 
|  | 10694 | address = Rn; | 
|  | 10695 | else | 
|  | 10696 | address = Rn - imm32; | 
|  | 10697 |  | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 10698 | // if wback then R[n] = if add then R[n]+imm32 else R[n]-imm32; | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 10699 | EmulateInstruction::Context context; | 
|  | 10700 |  | 
|  | 10701 | if (wback) | 
|  | 10702 | { | 
|  | 10703 | uint32_t value; | 
|  | 10704 | if (add) | 
|  | 10705 | value = Rn + imm32; | 
|  | 10706 | else | 
|  | 10707 | value = Rn - imm32; | 
|  | 10708 |  | 
|  | 10709 | context.type = eContextAdjustBaseRegister; | 
|  | 10710 | context.SetImmediateSigned (value - Rn); | 
|  | 10711 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, value)) | 
|  | 10712 | return false; | 
|  | 10713 |  | 
|  | 10714 | } | 
|  | 10715 |  | 
|  | 10716 | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  | 10717 | uint32_t start_reg = single_regs ? dwarf_s0 : dwarf_d0; | 
|  | 10718 |  | 
|  | 10719 | context.type = eContextRegisterLoad; | 
|  | 10720 |  | 
|  | 10721 | // for r = 0 to regs-1 | 
| Caroline Tice | bf5a66b | 2011-03-31 03:26:23 +0000 | [diff] [blame] | 10722 | for (uint32_t r = 0; r < regs; ++r) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 10723 | { | 
|  | 10724 | if (single_regs) | 
|  | 10725 | { | 
|  | 10726 | // S[d+r] = MemA[address,4]; address = address+4; | 
|  | 10727 | context.SetRegisterPlusOffset (base_reg, address - Rn); | 
|  | 10728 |  | 
|  | 10729 | uint32_t data = MemARead (context, address, addr_byte_size, 0, &success); | 
|  | 10730 | if (!success) | 
|  | 10731 | return false; | 
|  | 10732 |  | 
|  | 10733 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, start_reg + d + r, data)) | 
|  | 10734 | return false; | 
|  | 10735 |  | 
|  | 10736 | address = address + 4; | 
|  | 10737 | } | 
|  | 10738 | else | 
|  | 10739 | { | 
|  | 10740 | // word1 = MemA[address,4]; word2 = MemA[address+4,4]; address = address+8; | 
|  | 10741 | context.SetRegisterPlusOffset (base_reg, address - Rn); | 
|  | 10742 | uint32_t word1 = MemARead (context, address, addr_byte_size, 0, &success); | 
|  | 10743 | if (!success) | 
|  | 10744 | return false; | 
|  | 10745 |  | 
|  | 10746 | context.SetRegisterPlusOffset (base_reg, (address + 4) - Rn); | 
|  | 10747 | uint32_t word2 = MemARead (context, address + 4, addr_byte_size, 0, &success); | 
|  | 10748 | if (!success) | 
|  | 10749 | return false; | 
|  | 10750 |  | 
|  | 10751 | address = address + 8; | 
|  | 10752 | // // Combine the word-aligned words in the correct order for current endianness. | 
|  | 10753 | // D[d+r] = if BigEndian() then word1:word2 else word2:word1; | 
|  | 10754 | uint64_t data; | 
| Greg Clayton | 888a733 | 2011-04-26 04:39:08 +0000 | [diff] [blame] | 10755 | if (GetByteOrder() == eByteOrderBig) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 10756 | { | 
|  | 10757 | data = word1; | 
|  | 10758 | data = (data << 32) | word2; | 
|  | 10759 | } | 
|  | 10760 | else | 
|  | 10761 | { | 
|  | 10762 | data = word2; | 
|  | 10763 | data = (data << 32) | word1; | 
|  | 10764 | } | 
|  | 10765 |  | 
|  | 10766 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, start_reg + d + r, data)) | 
|  | 10767 | return false; | 
|  | 10768 | } | 
|  | 10769 | } | 
|  | 10770 | } | 
|  | 10771 | return true; | 
|  | 10772 | } | 
| Caroline Tice | bf5a66b | 2011-03-31 03:26:23 +0000 | [diff] [blame] | 10773 |  | 
|  | 10774 | // A8.6.399 VSTM | 
| Caroline Tice | 917ad35 | 2011-03-31 05:05:30 +0000 | [diff] [blame] | 10775 | // Vector Store Multiple stores multiple extension registers to consecutive memory locations using an address from an | 
|  | 10776 | // ARM core register. | 
| Caroline Tice | bf5a66b | 2011-03-31 03:26:23 +0000 | [diff] [blame] | 10777 | bool | 
|  | 10778 | EmulateInstructionARM::EmulateVSTM (const uint32_t opcode, const ARMEncoding encoding) | 
|  | 10779 | { | 
|  | 10780 | #if 0 | 
|  | 10781 | if ConditionPassed() then | 
|  | 10782 | EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(n); | 
|  | 10783 | address = if add then R[n] else R[n]-imm32; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 10784 | if wback then R[n] = if add then R[n]+imm32 else R[n]-imm32; | 
| Caroline Tice | bf5a66b | 2011-03-31 03:26:23 +0000 | [diff] [blame] | 10785 | for r = 0 to regs-1 | 
|  | 10786 | if single_regs then | 
|  | 10787 | MemA[address,4] = S[d+r]; address = address+4; | 
|  | 10788 | else | 
|  | 10789 | // Store as two word-aligned words in the correct order for current endianness. | 
|  | 10790 | MemA[address,4] = if BigEndian() then D[d+r]<63:32> else D[d+r]<31:0>; | 
|  | 10791 | MemA[address+4,4] = if BigEndian() then D[d+r]<31:0> else D[d+r]<63:32>; | 
|  | 10792 | address = address+8; | 
|  | 10793 | #endif | 
|  | 10794 |  | 
|  | 10795 | bool success = false; | 
|  | 10796 |  | 
|  | 10797 | if (ConditionPassed (opcode)) | 
|  | 10798 | { | 
|  | 10799 | bool single_regs; | 
|  | 10800 | bool add; | 
|  | 10801 | bool wback; | 
|  | 10802 | uint32_t d; | 
|  | 10803 | uint32_t n; | 
|  | 10804 | uint32_t imm32; | 
|  | 10805 | uint32_t regs; | 
|  | 10806 |  | 
|  | 10807 | switch (encoding) | 
|  | 10808 | { | 
|  | 10809 | case eEncodingT1: | 
|  | 10810 | case eEncodingA1: | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 10811 | // if P == Ô0Õ && U == Ô0Õ && W == Ô0Õ then SEE ÒRelated encodingsÓ; | 
|  | 10812 | // if P == Ô1Õ && U == Ô0Õ && W == Ô1Õ && Rn == Ô1101Õ then SEE VPUSH; | 
|  | 10813 | // if P == Ô1Õ && W == Ô0Õ then SEE VSTR; | 
|  | 10814 | // if P == U && W == Ô1Õ then UNDEFINED; | 
| Caroline Tice | bf5a66b | 2011-03-31 03:26:23 +0000 | [diff] [blame] | 10815 | if ((Bit32 (opcode, 24) == Bit32 (opcode, 23)) && BitIsSet (opcode, 21)) | 
|  | 10816 | return false; | 
|  | 10817 |  | 
|  | 10818 | // // Remaining combinations are PUW = 010 (IA without !), 011 (IA with !), 101 (DB with !) | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 10819 | // single_regs = FALSE; add = (U == Ô1Õ); wback = (W == Ô1Õ); | 
| Caroline Tice | bf5a66b | 2011-03-31 03:26:23 +0000 | [diff] [blame] | 10820 | single_regs = false; | 
|  | 10821 | add = BitIsSet (opcode, 23); | 
|  | 10822 | wback = BitIsSet (opcode, 21); | 
|  | 10823 |  | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 10824 | // d = UInt(D:Vd); n = UInt(Rn); imm32 = ZeroExtend(imm8:Õ00Õ, 32); | 
| Caroline Tice | bf5a66b | 2011-03-31 03:26:23 +0000 | [diff] [blame] | 10825 | d = (Bit32 (opcode, 22) << 4) | Bits32 (opcode, 15, 12); | 
|  | 10826 | n = Bits32 (opcode, 19, 16); | 
|  | 10827 | imm32 = Bits32 (opcode, 7, 0) << 2; | 
|  | 10828 |  | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 10829 | // regs = UInt(imm8) DIV 2; // If UInt(imm8) is odd, see ÒFSTMXÓ. | 
| Caroline Tice | bf5a66b | 2011-03-31 03:26:23 +0000 | [diff] [blame] | 10830 | regs = Bits32 (opcode, 7, 0) / 2; | 
|  | 10831 |  | 
|  | 10832 | // if n == 15 && (wback || CurrentInstrSet() != InstrSet_ARM) then UNPREDICTABLE; | 
|  | 10833 | if ((n == 15) && (wback || (CurrentInstrSet() != eModeARM))) | 
|  | 10834 | return false; | 
|  | 10835 |  | 
|  | 10836 | // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE; | 
|  | 10837 | if ((regs == 0) || (regs > 16) || ((d + regs) > 32)) | 
|  | 10838 | return false; | 
|  | 10839 |  | 
|  | 10840 | break; | 
|  | 10841 |  | 
|  | 10842 | case eEncodingT2: | 
|  | 10843 | case eEncodingA2: | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 10844 | // if P == Ô0Õ && U == Ô0Õ && W == Ô0Õ then SEE ÒRelated encodingsÓ; | 
|  | 10845 | // if P == Ô1Õ && U == Ô0Õ && W == Ô1Õ && Rn == Ô1101Õ then SEE VPUSH; | 
|  | 10846 | // if P == Ô1Õ && W == Ô0Õ then SEE VSTR; | 
|  | 10847 | // if P == U && W == Ô1Õ then UNDEFINED; | 
| Caroline Tice | bf5a66b | 2011-03-31 03:26:23 +0000 | [diff] [blame] | 10848 | if ((Bit32 (opcode, 24) == Bit32 (opcode, 23)) && BitIsSet (opcode, 21)) | 
|  | 10849 | return false; | 
|  | 10850 |  | 
|  | 10851 | // // Remaining combinations are PUW = 010 (IA without !), 011 (IA with !), 101 (DB with !) | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 10852 | // single_regs = TRUE; add = (U == Ô1Õ); wback = (W == Ô1Õ); d = UInt(Vd:D); n = UInt(Rn); | 
| Caroline Tice | bf5a66b | 2011-03-31 03:26:23 +0000 | [diff] [blame] | 10853 | single_regs = true; | 
|  | 10854 | add = BitIsSet (opcode, 23); | 
|  | 10855 | wback = BitIsSet (opcode, 21); | 
|  | 10856 | d = (Bits32 (opcode, 15, 12) << 1) | Bit32 (opcode, 22); | 
|  | 10857 | n = Bits32 (opcode, 19, 16); | 
|  | 10858 |  | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 10859 | // imm32 = ZeroExtend(imm8:Õ00Õ, 32); regs = UInt(imm8); | 
| Caroline Tice | bf5a66b | 2011-03-31 03:26:23 +0000 | [diff] [blame] | 10860 | imm32 = Bits32 (opcode, 7, 0) << 2; | 
|  | 10861 | regs = Bits32 (opcode, 7, 0); | 
|  | 10862 |  | 
|  | 10863 | // if n == 15 && (wback || CurrentInstrSet() != InstrSet_ARM) then UNPREDICTABLE; | 
|  | 10864 | if ((n == 15) && (wback || (CurrentInstrSet () != eModeARM))) | 
|  | 10865 | return false; | 
|  | 10866 |  | 
|  | 10867 | // if regs == 0 || (d+regs) > 32 then UNPREDICTABLE; | 
|  | 10868 | if ((regs == 0) || ((d + regs) > 32)) | 
|  | 10869 | return false; | 
|  | 10870 |  | 
|  | 10871 | break; | 
|  | 10872 |  | 
|  | 10873 | default: | 
|  | 10874 | return false; | 
|  | 10875 | } | 
|  | 10876 |  | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 10877 | RegisterInfo base_reg; | 
|  | 10878 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
| Caroline Tice | bf5a66b | 2011-03-31 03:26:23 +0000 | [diff] [blame] | 10879 |  | 
|  | 10880 | uint32_t Rn = ReadCoreReg (n, &success); | 
|  | 10881 | if (!success) | 
|  | 10882 | return false; | 
|  | 10883 |  | 
|  | 10884 | // address = if add then R[n] else R[n]-imm32; | 
|  | 10885 | addr_t address; | 
|  | 10886 | if (add) | 
|  | 10887 | address = Rn; | 
|  | 10888 | else | 
|  | 10889 | address = Rn - imm32; | 
|  | 10890 |  | 
|  | 10891 | EmulateInstruction::Context context; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 10892 | // if wback then R[n] = if add then R[n]+imm32 else R[n]-imm32; | 
| Caroline Tice | bf5a66b | 2011-03-31 03:26:23 +0000 | [diff] [blame] | 10893 | if (wback) | 
|  | 10894 | { | 
|  | 10895 | uint32_t value; | 
|  | 10896 | if (add) | 
|  | 10897 | value = Rn + imm32; | 
|  | 10898 | else | 
|  | 10899 | value = Rn - imm32; | 
|  | 10900 |  | 
|  | 10901 | context.type = eContextAdjustBaseRegister; | 
|  | 10902 | context.SetRegisterPlusOffset (base_reg, value - Rn); | 
|  | 10903 |  | 
|  | 10904 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, value)) | 
|  | 10905 | return false; | 
|  | 10906 | } | 
|  | 10907 |  | 
|  | 10908 | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  | 10909 | uint32_t start_reg = single_regs ? dwarf_s0 : dwarf_d0; | 
|  | 10910 |  | 
|  | 10911 | context.type = eContextRegisterStore; | 
|  | 10912 | // for r = 0 to regs-1 | 
|  | 10913 | for (int r = 0; r < regs; ++r) | 
|  | 10914 | { | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 10915 |  | 
| Caroline Tice | bf5a66b | 2011-03-31 03:26:23 +0000 | [diff] [blame] | 10916 | if (single_regs) | 
|  | 10917 | { | 
|  | 10918 | // MemA[address,4] = S[d+r]; address = address+4; | 
|  | 10919 | uint32_t data = ReadRegisterUnsigned (eRegisterKindDWARF, start_reg + d + r, 0, &success); | 
|  | 10920 | if (!success) | 
|  | 10921 | return false; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 10922 |  | 
|  | 10923 | RegisterInfo data_reg; | 
|  | 10924 | GetRegisterInfo (eRegisterKindDWARF, start_reg + d + r, data_reg); | 
| Caroline Tice | bf5a66b | 2011-03-31 03:26:23 +0000 | [diff] [blame] | 10925 | context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, address - Rn); | 
|  | 10926 | if (!MemAWrite (context, address, data, addr_byte_size)) | 
|  | 10927 | return false; | 
|  | 10928 |  | 
|  | 10929 | address = address + 4; | 
|  | 10930 | } | 
|  | 10931 | else | 
|  | 10932 | { | 
|  | 10933 | // // Store as two word-aligned words in the correct order for current endianness. | 
|  | 10934 | // MemA[address,4] = if BigEndian() then D[d+r]<63:32> else D[d+r]<31:0>; | 
|  | 10935 | // MemA[address+4,4] = if BigEndian() then D[d+r]<31:0> else D[d+r]<63:32>; | 
|  | 10936 | uint64_t data = ReadRegisterUnsigned (eRegisterKindDWARF, start_reg + d + r, 0, &success); | 
|  | 10937 | if (!success) | 
|  | 10938 | return false; | 
|  | 10939 |  | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 10940 | RegisterInfo data_reg; | 
|  | 10941 | GetRegisterInfo (eRegisterKindDWARF, start_reg + d + r, data_reg); | 
| Caroline Tice | bf5a66b | 2011-03-31 03:26:23 +0000 | [diff] [blame] | 10942 |  | 
| Greg Clayton | 888a733 | 2011-04-26 04:39:08 +0000 | [diff] [blame] | 10943 | if (GetByteOrder() == eByteOrderBig) | 
| Caroline Tice | bf5a66b | 2011-03-31 03:26:23 +0000 | [diff] [blame] | 10944 | { | 
|  | 10945 | context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, address - Rn); | 
|  | 10946 | if (!MemAWrite (context, address, Bits64 (data, 63, 32), addr_byte_size)) | 
|  | 10947 | return false; | 
|  | 10948 |  | 
|  | 10949 | context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, (address + 4) - Rn); | 
|  | 10950 | if (!MemAWrite (context, address+ 4, Bits64 (data, 31, 0), addr_byte_size)) | 
|  | 10951 | return false; | 
|  | 10952 | } | 
|  | 10953 | else | 
|  | 10954 | { | 
|  | 10955 | context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, address - Rn); | 
|  | 10956 | if (!MemAWrite (context, address, Bits64 (data, 31, 0), addr_byte_size)) | 
|  | 10957 | return false; | 
|  | 10958 |  | 
|  | 10959 | context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, (address + 4) - Rn); | 
|  | 10960 | if (!MemAWrite (context, address + 4, Bits64 (data, 63, 32), addr_byte_size)) | 
|  | 10961 | return false; | 
|  | 10962 | } | 
|  | 10963 | // address = address+8; | 
|  | 10964 | address = address + 8; | 
|  | 10965 | } | 
|  | 10966 | } | 
|  | 10967 | } | 
|  | 10968 | return true; | 
|  | 10969 | } | 
|  | 10970 |  | 
| Caroline Tice | 917ad35 | 2011-03-31 05:05:30 +0000 | [diff] [blame] | 10971 | // A8.6.320 | 
|  | 10972 | // This instruciton loads a single extension register fronm memory, using an address from an ARM core register, with | 
|  | 10973 | // an optional offset. | 
|  | 10974 | bool | 
|  | 10975 | EmulateInstructionARM::EmulateVLDR (const uint32_t opcode, ARMEncoding encoding) | 
|  | 10976 | { | 
|  | 10977 | #if 0 | 
|  | 10978 | if ConditionPassed() then | 
|  | 10979 | EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(n); | 
|  | 10980 | base = if n == 15 then Align(PC,4) else R[n]; | 
|  | 10981 | address = if add then (base + imm32) else (base - imm32); | 
|  | 10982 | if single_reg then | 
|  | 10983 | S[d] = MemA[address,4]; | 
|  | 10984 | else | 
|  | 10985 | word1 = MemA[address,4]; word2 = MemA[address+4,4]; | 
|  | 10986 | // Combine the word-aligned words in the correct order for current endianness. | 
|  | 10987 | D[d] = if BigEndian() then word1:word2 else word2:word1; | 
|  | 10988 | #endif | 
|  | 10989 |  | 
|  | 10990 | bool success = false; | 
|  | 10991 |  | 
|  | 10992 | if (ConditionPassed (opcode)) | 
|  | 10993 | { | 
|  | 10994 | bool single_reg; | 
|  | 10995 | bool add; | 
|  | 10996 | uint32_t imm32; | 
|  | 10997 | uint32_t d; | 
|  | 10998 | uint32_t n; | 
|  | 10999 |  | 
|  | 11000 | switch (encoding) | 
|  | 11001 | { | 
|  | 11002 | case eEncodingT1: | 
|  | 11003 | case eEncodingA1: | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 11004 | // single_reg = FALSE; add = (U == Ô1Õ); imm32 = ZeroExtend(imm8:Õ00Õ, 32); | 
| Caroline Tice | 917ad35 | 2011-03-31 05:05:30 +0000 | [diff] [blame] | 11005 | single_reg = false; | 
|  | 11006 | add = BitIsSet (opcode, 23); | 
|  | 11007 | imm32 = Bits32 (opcode, 7, 0) << 2; | 
|  | 11008 |  | 
|  | 11009 | // d = UInt(D:Vd); n = UInt(Rn); | 
|  | 11010 | d = (Bit32 (opcode, 22) << 4) | Bits32 (opcode, 15, 12); | 
|  | 11011 | n = Bits32 (opcode, 19, 16); | 
|  | 11012 |  | 
|  | 11013 | break; | 
|  | 11014 |  | 
|  | 11015 | case eEncodingT2: | 
|  | 11016 | case eEncodingA2: | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 11017 | // single_reg = TRUE; add = (U == Ô1Õ); imm32 = ZeroExtend(imm8:Õ00Õ, 32); | 
| Caroline Tice | 917ad35 | 2011-03-31 05:05:30 +0000 | [diff] [blame] | 11018 | single_reg = true; | 
|  | 11019 | add = BitIsSet (opcode, 23); | 
|  | 11020 | imm32 = Bits32 (opcode, 7, 0) << 2; | 
|  | 11021 |  | 
|  | 11022 | // d = UInt(Vd:D); n = UInt(Rn); | 
|  | 11023 | d = (Bits32 (opcode, 15, 12) << 1) | Bit32 (opcode, 22); | 
|  | 11024 | n = Bits32 (opcode, 19, 16); | 
|  | 11025 |  | 
|  | 11026 | break; | 
|  | 11027 |  | 
|  | 11028 | default: | 
|  | 11029 | return false; | 
|  | 11030 | } | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 11031 | RegisterInfo base_reg; | 
|  | 11032 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
| Caroline Tice | 917ad35 | 2011-03-31 05:05:30 +0000 | [diff] [blame] | 11033 |  | 
|  | 11034 | uint32_t Rn = ReadCoreReg (n, &success); | 
|  | 11035 | if (!success) | 
|  | 11036 | return false; | 
|  | 11037 |  | 
|  | 11038 | // base = if n == 15 then Align(PC,4) else R[n]; | 
|  | 11039 | uint32_t base; | 
|  | 11040 | if (n == 15) | 
|  | 11041 | base = AlignPC (Rn); | 
|  | 11042 | else | 
|  | 11043 | base = Rn; | 
|  | 11044 |  | 
|  | 11045 | // address = if add then (base + imm32) else (base - imm32); | 
|  | 11046 | addr_t address; | 
|  | 11047 | if (add) | 
|  | 11048 | address = base + imm32; | 
|  | 11049 | else | 
|  | 11050 | address = base - imm32; | 
|  | 11051 |  | 
|  | 11052 | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  | 11053 | uint32_t start_reg = single_reg ? dwarf_s0 : dwarf_d0; | 
|  | 11054 |  | 
|  | 11055 | EmulateInstruction::Context context; | 
|  | 11056 | context.type = eContextRegisterLoad; | 
|  | 11057 | context.SetRegisterPlusOffset (base_reg, address - base); | 
| Caroline Tice | bf5a66b | 2011-03-31 03:26:23 +0000 | [diff] [blame] | 11058 |  | 
| Caroline Tice | 917ad35 | 2011-03-31 05:05:30 +0000 | [diff] [blame] | 11059 | if (single_reg) | 
|  | 11060 | { | 
|  | 11061 | // S[d] = MemA[address,4]; | 
|  | 11062 | uint32_t data = MemARead (context, address, addr_byte_size, 0, &success); | 
|  | 11063 | if (!success) | 
|  | 11064 | return false; | 
|  | 11065 |  | 
|  | 11066 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, start_reg + d, data)) | 
|  | 11067 | return false; | 
|  | 11068 | } | 
|  | 11069 | else | 
|  | 11070 | { | 
|  | 11071 | // word1 = MemA[address,4]; word2 = MemA[address+4,4]; | 
|  | 11072 | uint32_t word1 = MemARead (context, address, addr_byte_size, 0, &success); | 
|  | 11073 | if (!success) | 
|  | 11074 | return false; | 
|  | 11075 |  | 
|  | 11076 | context.SetRegisterPlusOffset (base_reg, (address + 4) - base); | 
|  | 11077 | uint32_t word2 = MemARead (context, address + 4, addr_byte_size, 0, &success); | 
|  | 11078 | if (!success) | 
|  | 11079 | return false; | 
|  | 11080 | // // Combine the word-aligned words in the correct order for current endianness. | 
|  | 11081 | // D[d] = if BigEndian() then word1:word2 else word2:word1; | 
|  | 11082 | uint64_t data64; | 
| Greg Clayton | 888a733 | 2011-04-26 04:39:08 +0000 | [diff] [blame] | 11083 | if (GetByteOrder() == eByteOrderBig) | 
| Caroline Tice | 917ad35 | 2011-03-31 05:05:30 +0000 | [diff] [blame] | 11084 | { | 
|  | 11085 | data64 = word1; | 
|  | 11086 | data64 = (data64 << 32) | word2; | 
|  | 11087 | } | 
|  | 11088 | else | 
|  | 11089 | { | 
|  | 11090 | data64 = word2; | 
|  | 11091 | data64 = (data64 << 32) | word1; | 
|  | 11092 | } | 
|  | 11093 |  | 
|  | 11094 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, start_reg + d, data64)) | 
|  | 11095 | return false; | 
|  | 11096 | } | 
|  | 11097 | } | 
|  | 11098 | return true; | 
|  | 11099 | } | 
| Caroline Tice | 424652f | 2011-03-31 05:38:36 +0000 | [diff] [blame] | 11100 |  | 
|  | 11101 | // A8.6.400 VSTR | 
|  | 11102 | // This instruction stores a signle extension register to memory, using an address from an ARM core register, with an | 
|  | 11103 | // optional offset. | 
|  | 11104 | bool | 
|  | 11105 | EmulateInstructionARM::EmulateVSTR (const uint32_t opcode, ARMEncoding encoding) | 
|  | 11106 | { | 
|  | 11107 | #if 0 | 
|  | 11108 | if ConditionPassed() then | 
|  | 11109 | EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(n); | 
|  | 11110 | address = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | 11111 | if single_reg then | 
|  | 11112 | MemA[address,4] = S[d]; | 
|  | 11113 | else | 
|  | 11114 | // Store as two word-aligned words in the correct order for current endianness. | 
|  | 11115 | MemA[address,4] = if BigEndian() then D[d]<63:32> else D[d]<31:0>; | 
|  | 11116 | MemA[address+4,4] = if BigEndian() then D[d]<31:0> else D[d]<63:32>; | 
|  | 11117 | #endif | 
|  | 11118 |  | 
|  | 11119 | bool success = false; | 
|  | 11120 |  | 
|  | 11121 | if (ConditionPassed (opcode)) | 
|  | 11122 | { | 
|  | 11123 | bool single_reg; | 
|  | 11124 | bool add; | 
|  | 11125 | uint32_t imm32; | 
|  | 11126 | uint32_t d; | 
|  | 11127 | uint32_t n; | 
|  | 11128 |  | 
|  | 11129 | switch (encoding) | 
|  | 11130 | { | 
|  | 11131 | case eEncodingT1: | 
|  | 11132 | case eEncodingA1: | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 11133 | // single_reg = FALSE; add = (U == Ô1Õ); imm32 = ZeroExtend(imm8:Õ00Õ, 32); | 
| Caroline Tice | 424652f | 2011-03-31 05:38:36 +0000 | [diff] [blame] | 11134 | single_reg = false; | 
|  | 11135 | add = BitIsSet (opcode, 23); | 
|  | 11136 | imm32 = Bits32 (opcode, 7, 0) << 2; | 
|  | 11137 |  | 
|  | 11138 | // d = UInt(D:Vd); n = UInt(Rn); | 
|  | 11139 | d = (Bit32 (opcode, 22) << 4) | Bits32 (opcode, 15, 12); | 
|  | 11140 | n = Bits32 (opcode, 19, 16); | 
|  | 11141 |  | 
|  | 11142 | // if n == 15 && CurrentInstrSet() != InstrSet_ARM then UNPREDICTABLE; | 
|  | 11143 | if ((n == 15) && (CurrentInstrSet() != eModeARM)) | 
|  | 11144 | return false; | 
|  | 11145 |  | 
|  | 11146 | break; | 
|  | 11147 |  | 
|  | 11148 | case eEncodingT2: | 
|  | 11149 | case eEncodingA2: | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 11150 | // single_reg = TRUE; add = (U == Ô1Õ); imm32 = ZeroExtend(imm8:Õ00Õ, 32); | 
| Caroline Tice | 424652f | 2011-03-31 05:38:36 +0000 | [diff] [blame] | 11151 | single_reg = true; | 
|  | 11152 | add = BitIsSet (opcode, 23); | 
|  | 11153 | imm32 = Bits32 (opcode, 7, 0) << 2; | 
|  | 11154 |  | 
|  | 11155 | // d = UInt(Vd:D); n = UInt(Rn); | 
|  | 11156 | d = (Bits32 (opcode, 15, 12) << 1) | Bit32 (opcode, 22); | 
|  | 11157 | n = Bits32 (opcode, 19, 16); | 
|  | 11158 |  | 
|  | 11159 | // if n == 15 && CurrentInstrSet() != InstrSet_ARM then UNPREDICTABLE; | 
|  | 11160 | if ((n == 15) && (CurrentInstrSet() != eModeARM)) | 
|  | 11161 | return false; | 
|  | 11162 |  | 
|  | 11163 | break; | 
|  | 11164 |  | 
|  | 11165 | default: | 
|  | 11166 | return false; | 
|  | 11167 | } | 
|  | 11168 |  | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 11169 | RegisterInfo base_reg; | 
|  | 11170 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
| Caroline Tice | 424652f | 2011-03-31 05:38:36 +0000 | [diff] [blame] | 11171 |  | 
|  | 11172 | uint32_t Rn = ReadCoreReg (n, &success); | 
|  | 11173 | if (!success) | 
|  | 11174 | return false; | 
|  | 11175 |  | 
|  | 11176 | // address = if add then (R[n] + imm32) else (R[n] - imm32); | 
|  | 11177 | addr_t address; | 
|  | 11178 | if (add) | 
|  | 11179 | address = Rn + imm32; | 
|  | 11180 | else | 
|  | 11181 | address = Rn - imm32; | 
|  | 11182 |  | 
|  | 11183 | const uint32_t addr_byte_size = GetAddressByteSize(); | 
|  | 11184 | uint32_t start_reg = single_reg ? dwarf_s0 : dwarf_d0; | 
|  | 11185 |  | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 11186 | RegisterInfo data_reg; | 
|  | 11187 | GetRegisterInfo (eRegisterKindDWARF, start_reg + d, data_reg); | 
| Caroline Tice | 424652f | 2011-03-31 05:38:36 +0000 | [diff] [blame] | 11188 | EmulateInstruction::Context context; | 
|  | 11189 | context.type = eContextRegisterStore; | 
|  | 11190 | context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, address - Rn); | 
|  | 11191 |  | 
|  | 11192 | if (single_reg) | 
|  | 11193 | { | 
|  | 11194 | // MemA[address,4] = S[d]; | 
|  | 11195 | uint32_t data = ReadRegisterUnsigned (eRegisterKindDWARF, start_reg + d, 0, &success); | 
|  | 11196 | if (!success) | 
|  | 11197 | return false; | 
|  | 11198 |  | 
|  | 11199 | if (!MemAWrite (context, address, data, addr_byte_size)) | 
|  | 11200 | return false; | 
|  | 11201 | } | 
|  | 11202 | else | 
|  | 11203 | { | 
|  | 11204 | // // Store as two word-aligned words in the correct order for current endianness. | 
|  | 11205 | // MemA[address,4] = if BigEndian() then D[d]<63:32> else D[d]<31:0>; | 
|  | 11206 | // MemA[address+4,4] = if BigEndian() then D[d]<31:0> else D[d]<63:32>; | 
|  | 11207 | uint64_t data = ReadRegisterUnsigned (eRegisterKindDWARF, start_reg + d, 0, &success); | 
|  | 11208 | if (!success) | 
|  | 11209 | return false; | 
|  | 11210 |  | 
| Greg Clayton | 888a733 | 2011-04-26 04:39:08 +0000 | [diff] [blame] | 11211 | if (GetByteOrder() == eByteOrderBig) | 
| Caroline Tice | 424652f | 2011-03-31 05:38:36 +0000 | [diff] [blame] | 11212 | { | 
|  | 11213 | if (!MemAWrite (context, address, Bits64 (data, 63, 32), addr_byte_size)) | 
|  | 11214 | return false; | 
|  | 11215 |  | 
|  | 11216 | context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, (address + 4) - Rn); | 
|  | 11217 | if (!MemAWrite (context, address + 4, Bits64 (data, 31, 0), addr_byte_size)) | 
|  | 11218 | return false; | 
|  | 11219 | } | 
|  | 11220 | else | 
|  | 11221 | { | 
|  | 11222 | if (!MemAWrite (context, address, Bits64 (data, 31, 0), addr_byte_size)) | 
|  | 11223 | return false; | 
|  | 11224 |  | 
|  | 11225 | context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, (address + 4) - Rn); | 
|  | 11226 | if (!MemAWrite (context, address + 4, Bits64 (data, 63, 32), addr_byte_size)) | 
|  | 11227 | return false; | 
|  | 11228 | } | 
|  | 11229 | } | 
|  | 11230 | } | 
|  | 11231 | return true; | 
|  | 11232 | } | 
| Caroline Tice | 9121b35 | 2011-03-31 16:41:19 +0000 | [diff] [blame] | 11233 |  | 
|  | 11234 | // A8.6.307 VLDI1 (multiple single elements) | 
|  | 11235 | // This instruction loads elements from memory into one, two, three or four registers, without de-interleaving.  Every | 
|  | 11236 | // element of each register is loaded. | 
|  | 11237 | bool | 
|  | 11238 | EmulateInstructionARM::EmulateVLD1Multiple (const uint32_t opcode, ARMEncoding encoding) | 
|  | 11239 | { | 
|  | 11240 | #if 0 | 
|  | 11241 | if ConditionPassed() then | 
|  | 11242 | EncodingSpecificOperations(); CheckAdvSIMDEnabled(); NullCheckIfThumbEE(n); | 
|  | 11243 | address = R[n]; if (address MOD alignment) != 0 then GenerateAlignmentException(); | 
|  | 11244 | if wback then R[n] = R[n] + (if register_index then R[m] else 8*regs); | 
|  | 11245 | for r = 0 to regs-1 | 
|  | 11246 | for e = 0 to elements-1 | 
|  | 11247 | Elem[D[d+r],e,esize] = MemU[address,ebytes]; | 
|  | 11248 | address = address + ebytes; | 
|  | 11249 | #endif | 
|  | 11250 |  | 
|  | 11251 | bool success = false; | 
|  | 11252 |  | 
|  | 11253 | if (ConditionPassed (opcode)) | 
|  | 11254 | { | 
|  | 11255 | uint32_t regs; | 
|  | 11256 | uint32_t alignment; | 
|  | 11257 | uint32_t ebytes; | 
|  | 11258 | uint32_t esize; | 
|  | 11259 | uint32_t elements; | 
|  | 11260 | uint32_t d; | 
|  | 11261 | uint32_t n; | 
|  | 11262 | uint32_t m; | 
|  | 11263 | bool wback; | 
|  | 11264 | bool register_index; | 
|  | 11265 |  | 
|  | 11266 | switch (encoding) | 
|  | 11267 | { | 
|  | 11268 | case eEncodingT1: | 
|  | 11269 | case eEncodingA1: | 
|  | 11270 | { | 
|  | 11271 | // case type of | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 11272 | // when Ô0111Õ | 
|  | 11273 | // regs = 1; if align<1> == Ô1Õ then UNDEFINED; | 
|  | 11274 | // when Ô1010Õ | 
|  | 11275 | // regs = 2; if align == Ô11Õ then UNDEFINED; | 
|  | 11276 | // when Ô0110Õ | 
|  | 11277 | // regs = 3; if align<1> == Ô1Õ then UNDEFINED; | 
|  | 11278 | // when Ô0010Õ | 
| Caroline Tice | 9121b35 | 2011-03-31 16:41:19 +0000 | [diff] [blame] | 11279 | // regs = 4; | 
|  | 11280 | // otherwise | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 11281 | // SEE ÒRelated encodingsÓ; | 
| Caroline Tice | 9121b35 | 2011-03-31 16:41:19 +0000 | [diff] [blame] | 11282 | uint32_t type = Bits32 (opcode, 11, 8); | 
|  | 11283 | uint32_t align = Bits32 (opcode, 5, 4); | 
|  | 11284 | if (type == 7) // '0111' | 
|  | 11285 | { | 
|  | 11286 | regs = 1; | 
|  | 11287 | if (BitIsSet (align, 1)) | 
|  | 11288 | return false; | 
|  | 11289 | } | 
|  | 11290 | else if (type == 10) // '1010' | 
|  | 11291 | { | 
|  | 11292 | regs = 2; | 
|  | 11293 | if (align == 3) | 
|  | 11294 | return false; | 
|  | 11295 |  | 
|  | 11296 | } | 
|  | 11297 | else if (type == 6) // '0110' | 
|  | 11298 | { | 
|  | 11299 | regs = 3; | 
|  | 11300 | if (BitIsSet (align, 1)) | 
|  | 11301 | return false; | 
|  | 11302 | } | 
|  | 11303 | else if (type == 2) // '0010' | 
|  | 11304 | { | 
|  | 11305 | regs = 4; | 
|  | 11306 | } | 
|  | 11307 | else | 
|  | 11308 | return false; | 
|  | 11309 |  | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 11310 | // alignment = if align == Ô00Õ then 1 else 4 << UInt(align); | 
| Caroline Tice | 9121b35 | 2011-03-31 16:41:19 +0000 | [diff] [blame] | 11311 | if (align == 0) | 
|  | 11312 | alignment = 1; | 
|  | 11313 | else | 
|  | 11314 | alignment = 4 << align; | 
|  | 11315 |  | 
|  | 11316 | // ebytes = 1 << UInt(size); esize = 8 * ebytes; elements = 8 DIV ebytes; | 
|  | 11317 | ebytes = 1 << Bits32 (opcode, 7, 6); | 
|  | 11318 | esize = 8 * ebytes; | 
|  | 11319 | elements = 8 / ebytes; | 
|  | 11320 |  | 
|  | 11321 | // d = UInt(D:Vd); n = UInt(Rn); m = UInt(Rm); | 
|  | 11322 | d = (Bit32 (opcode, 22) << 4) | Bits32 (opcode, 15, 12); | 
|  | 11323 | n = Bits32 (opcode, 19, 15); | 
|  | 11324 | m = Bits32 (opcode, 3, 0); | 
|  | 11325 |  | 
|  | 11326 | // wback = (m != 15); register_index = (m != 15 && m != 13); | 
|  | 11327 | wback = (m != 15); | 
|  | 11328 | register_index = ((m != 15) && (m != 13)); | 
|  | 11329 |  | 
|  | 11330 | // if d+regs > 32 then UNPREDICTABLE; | 
|  | 11331 | if ((d + regs) > 32) | 
|  | 11332 | return false; | 
|  | 11333 | } | 
|  | 11334 | break; | 
|  | 11335 |  | 
|  | 11336 | default: | 
|  | 11337 | return false; | 
|  | 11338 | } | 
|  | 11339 |  | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 11340 | RegisterInfo base_reg; | 
|  | 11341 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
| Caroline Tice | 9121b35 | 2011-03-31 16:41:19 +0000 | [diff] [blame] | 11342 |  | 
|  | 11343 | uint32_t Rn = ReadCoreReg (n, &success); | 
|  | 11344 | if (!success) | 
|  | 11345 | return false; | 
|  | 11346 |  | 
|  | 11347 | // address = R[n]; if (address MOD alignment) != 0 then GenerateAlignmentException(); | 
|  | 11348 | addr_t address = Rn; | 
|  | 11349 | if ((address % alignment) != 0) | 
|  | 11350 | return false; | 
|  | 11351 |  | 
|  | 11352 | EmulateInstruction::Context context; | 
|  | 11353 | // if wback then R[n] = R[n] + (if register_index then R[m] else 8*regs); | 
|  | 11354 | if (wback) | 
|  | 11355 | { | 
|  | 11356 | uint32_t Rm = ReadCoreReg (m, &success); | 
|  | 11357 | if (!success) | 
|  | 11358 | return false; | 
|  | 11359 |  | 
|  | 11360 | uint32_t offset; | 
|  | 11361 | if (register_index) | 
|  | 11362 | offset = Rm; | 
|  | 11363 | else | 
|  | 11364 | offset = 8 * regs; | 
|  | 11365 |  | 
|  | 11366 | uint32_t value = Rn + offset; | 
|  | 11367 | context.type = eContextAdjustBaseRegister; | 
|  | 11368 | context.SetRegisterPlusOffset (base_reg, offset); | 
|  | 11369 |  | 
|  | 11370 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, value)) | 
|  | 11371 | return false; | 
|  | 11372 |  | 
|  | 11373 | } | 
|  | 11374 |  | 
|  | 11375 | // for r = 0 to regs-1 | 
|  | 11376 | for (int r = 0; r < regs; ++r) | 
|  | 11377 | { | 
|  | 11378 | // for e = 0 to elements-1 | 
|  | 11379 | uint64_t assembled_data = 0; | 
|  | 11380 | for (int e = 0; e < elements; ++e) | 
|  | 11381 | { | 
|  | 11382 | // Elem[D[d+r],e,esize] = MemU[address,ebytes]; | 
|  | 11383 | context.type = eContextRegisterLoad; | 
|  | 11384 | context.SetRegisterPlusOffset (base_reg, address - Rn); | 
|  | 11385 | uint64_t data = MemURead (context, address, ebytes, 0, &success); | 
|  | 11386 | if (!success) | 
|  | 11387 | return false; | 
|  | 11388 |  | 
|  | 11389 | assembled_data = (data << (e * esize)) | assembled_data; // New data goes to the left of existing data | 
|  | 11390 |  | 
|  | 11391 | // address = address + ebytes; | 
|  | 11392 | address = address + ebytes; | 
|  | 11393 | } | 
|  | 11394 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_d0 + d + r, assembled_data)) | 
|  | 11395 | return false; | 
|  | 11396 | } | 
|  | 11397 | } | 
|  | 11398 | return true; | 
|  | 11399 | } | 
|  | 11400 |  | 
| Caroline Tice | b6281b1 | 2011-03-31 17:58:23 +0000 | [diff] [blame] | 11401 | // A8.6.308 VLD1 (single element to one lane) | 
|  | 11402 | // | 
|  | 11403 | bool | 
|  | 11404 | EmulateInstructionARM::EmulateVLD1Single (const uint32_t opcode, const ARMEncoding encoding) | 
|  | 11405 | { | 
|  | 11406 | #if 0 | 
|  | 11407 | if ConditionPassed() then | 
|  | 11408 | EncodingSpecificOperations(); CheckAdvSIMDEnabled(); NullCheckIfThumbEE(n); | 
|  | 11409 | address = R[n]; if (address MOD alignment) != 0 then GenerateAlignmentException(); | 
|  | 11410 | if wback then R[n] = R[n] + (if register_index then R[m] else ebytes); | 
|  | 11411 | Elem[D[d],index,esize] = MemU[address,ebytes]; | 
|  | 11412 | #endif | 
|  | 11413 |  | 
|  | 11414 | bool success = false; | 
|  | 11415 |  | 
|  | 11416 | if (ConditionPassed (opcode)) | 
|  | 11417 | { | 
|  | 11418 | uint32_t ebytes; | 
|  | 11419 | uint32_t esize; | 
|  | 11420 | uint32_t index; | 
|  | 11421 | uint32_t alignment; | 
|  | 11422 | uint32_t d; | 
|  | 11423 | uint32_t n; | 
|  | 11424 | uint32_t m; | 
|  | 11425 | bool wback; | 
|  | 11426 | bool register_index; | 
|  | 11427 |  | 
|  | 11428 | switch (encoding) | 
|  | 11429 | { | 
|  | 11430 | case eEncodingT1: | 
|  | 11431 | case eEncodingA1: | 
|  | 11432 | { | 
|  | 11433 | uint32_t size = Bits32 (opcode, 11, 10); | 
|  | 11434 | uint32_t index_align = Bits32 (opcode, 7, 4); | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 11435 | // if size == Ô11Õ then SEE VLD1 (single element to all lanes); | 
| Caroline Tice | 8d24b4a | 2011-03-31 21:31:50 +0000 | [diff] [blame] | 11436 | if (size == 3) | 
|  | 11437 | return EmulateVLD1SingleAll (opcode, encoding); | 
| Caroline Tice | b6281b1 | 2011-03-31 17:58:23 +0000 | [diff] [blame] | 11438 | // case size of | 
|  | 11439 | if (size == 0) // when '00' | 
|  | 11440 | { | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 11441 | // if index_align<0> != Ô0Õ then UNDEFINED; | 
| Caroline Tice | b6281b1 | 2011-03-31 17:58:23 +0000 | [diff] [blame] | 11442 | if (BitIsClear (index_align, 0)) | 
|  | 11443 | return false; | 
|  | 11444 |  | 
|  | 11445 | // ebytes = 1; esize = 8; index = UInt(index_align<3:1>); alignment = 1; | 
|  | 11446 | ebytes = 1; | 
|  | 11447 | esize = 8; | 
|  | 11448 | index = Bits32 (index_align, 3, 1); | 
|  | 11449 | alignment = 1; | 
|  | 11450 | } | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 11451 | else if (size == 1) // when Ô01Õ | 
| Caroline Tice | b6281b1 | 2011-03-31 17:58:23 +0000 | [diff] [blame] | 11452 | { | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 11453 | // if index_align<1> != Ô0Õ then UNDEFINED; | 
| Caroline Tice | b6281b1 | 2011-03-31 17:58:23 +0000 | [diff] [blame] | 11454 | if (BitIsClear (index_align, 1)) | 
|  | 11455 | return false; | 
|  | 11456 |  | 
|  | 11457 | // ebytes = 2; esize = 16; index = UInt(index_align<3:2>); | 
|  | 11458 | ebytes = 2; | 
|  | 11459 | esize = 16; | 
|  | 11460 | index = Bits32 (index_align, 3, 2); | 
|  | 11461 |  | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 11462 | // alignment = if index_align<0> == Ô0Õ then 1 else 2; | 
| Caroline Tice | b6281b1 | 2011-03-31 17:58:23 +0000 | [diff] [blame] | 11463 | if (BitIsClear (index_align, 0)) | 
|  | 11464 | alignment = 1; | 
|  | 11465 | else | 
|  | 11466 | alignment = 2; | 
|  | 11467 | } | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 11468 | else if (size == 2) // when Ô10Õ | 
| Caroline Tice | b6281b1 | 2011-03-31 17:58:23 +0000 | [diff] [blame] | 11469 | { | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 11470 | // if index_align<2> != Ô0Õ then UNDEFINED; | 
| Caroline Tice | b6281b1 | 2011-03-31 17:58:23 +0000 | [diff] [blame] | 11471 | if (BitIsClear (index_align, 2)) | 
|  | 11472 | return false; | 
|  | 11473 |  | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 11474 | // if index_align<1:0> != Ô00Õ && index_align<1:0> != Ô11Õ then UNDEFINED; | 
| Caroline Tice | b6281b1 | 2011-03-31 17:58:23 +0000 | [diff] [blame] | 11475 | if ((Bits32 (index_align, 1, 0) != 0) && (Bits32 (index_align, 1, 0) != 3)) | 
|  | 11476 | return false; | 
|  | 11477 |  | 
|  | 11478 | // ebytes = 4; esize = 32; index = UInt(index_align<3>); | 
|  | 11479 | ebytes = 4; | 
|  | 11480 | esize = 32; | 
|  | 11481 | index = Bit32 (index_align, 3); | 
|  | 11482 |  | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 11483 | // alignment = if index_align<1:0> == Ô00Õ then 1 else 4; | 
| Caroline Tice | b6281b1 | 2011-03-31 17:58:23 +0000 | [diff] [blame] | 11484 | if (Bits32 (index_align, 1, 0) == 0) | 
|  | 11485 | alignment = 1; | 
|  | 11486 | else | 
|  | 11487 | alignment = 4; | 
|  | 11488 | } | 
|  | 11489 | // d = UInt(D:Vd); n = UInt(Rn); m = UInt(Rm); | 
|  | 11490 | d = (Bit32 (opcode, 22) << 4) | Bits32 (opcode, 15, 12); | 
|  | 11491 | n = Bits32 (opcode, 19, 16); | 
|  | 11492 | m = Bits32 (opcode, 3, 0); | 
|  | 11493 |  | 
|  | 11494 | // wback = (m != 15); register_index = (m != 15 && m != 13); if n == 15 then UNPREDICTABLE; | 
|  | 11495 | wback = (m != 15); | 
|  | 11496 | register_index = ((m != 15) && (m != 13)); | 
|  | 11497 |  | 
|  | 11498 | if (n == 15) | 
|  | 11499 | return false; | 
|  | 11500 |  | 
|  | 11501 | } | 
|  | 11502 | break; | 
|  | 11503 |  | 
|  | 11504 | default: | 
|  | 11505 | return false; | 
|  | 11506 | } | 
|  | 11507 |  | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 11508 | RegisterInfo base_reg; | 
|  | 11509 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
| Caroline Tice | b6281b1 | 2011-03-31 17:58:23 +0000 | [diff] [blame] | 11510 |  | 
|  | 11511 | uint32_t Rn = ReadCoreReg (n, &success); | 
|  | 11512 | if (!success) | 
|  | 11513 | return false; | 
|  | 11514 |  | 
|  | 11515 | // address = R[n]; if (address MOD alignment) != 0 then GenerateAlignmentException(); | 
|  | 11516 | addr_t address = Rn; | 
|  | 11517 | if ((address % alignment) != 0) | 
|  | 11518 | return false; | 
|  | 11519 |  | 
|  | 11520 | EmulateInstruction::Context context; | 
|  | 11521 | // if wback then R[n] = R[n] + (if register_index then R[m] else ebytes); | 
|  | 11522 | if (wback) | 
|  | 11523 | { | 
|  | 11524 | uint32_t Rm = ReadCoreReg (m, &success); | 
|  | 11525 | if (!success) | 
|  | 11526 | return false; | 
|  | 11527 |  | 
|  | 11528 | uint32_t offset; | 
|  | 11529 | if (register_index) | 
|  | 11530 | offset = Rm; | 
|  | 11531 | else | 
|  | 11532 | offset = ebytes; | 
|  | 11533 |  | 
|  | 11534 | uint32_t value = Rn + offset; | 
|  | 11535 |  | 
|  | 11536 | context.type = eContextAdjustBaseRegister; | 
|  | 11537 | context.SetRegisterPlusOffset (base_reg, offset); | 
|  | 11538 |  | 
|  | 11539 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, value)) | 
|  | 11540 | return false; | 
|  | 11541 | } | 
|  | 11542 |  | 
|  | 11543 | // Elem[D[d],index,esize] = MemU[address,ebytes]; | 
|  | 11544 | uint32_t element = MemURead (context, address, esize, 0, &success); | 
|  | 11545 | if (!success) | 
|  | 11546 | return false; | 
|  | 11547 |  | 
|  | 11548 | element = element << (index * esize); | 
|  | 11549 |  | 
|  | 11550 | uint64_t reg_data = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_d0 + d, 0, &success); | 
|  | 11551 | if (!success) | 
|  | 11552 | return false; | 
|  | 11553 |  | 
|  | 11554 | uint64_t all_ones = -1; | 
|  | 11555 | uint64_t mask = all_ones << ((index+1) * esize);  // mask is all 1's to left of where 'element' goes, & all 0's | 
|  | 11556 | // at element & to the right of element. | 
|  | 11557 | if (index > 0) | 
| Caroline Tice | 7b88094 | 2011-03-31 19:17:12 +0000 | [diff] [blame] | 11558 | mask = mask | Bits64 (all_ones, (index * esize) - 1, 0); // add 1's to the right of where 'element' goes. | 
| Caroline Tice | b6281b1 | 2011-03-31 17:58:23 +0000 | [diff] [blame] | 11559 | // now mask should be 0's where element goes & 1's | 
|  | 11560 | // everywhere else. | 
|  | 11561 |  | 
|  | 11562 | uint64_t masked_reg = reg_data & mask;  // Take original reg value & zero out 'element' bits | 
|  | 11563 | reg_data = masked_reg & element;        // Put 'element' into those bits in reg_data. | 
|  | 11564 |  | 
|  | 11565 | context.type = eContextRegisterLoad; | 
|  | 11566 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + d, reg_data)) | 
|  | 11567 | return false; | 
|  | 11568 | } | 
|  | 11569 | return true; | 
|  | 11570 | } | 
|  | 11571 |  | 
| Caroline Tice | 1e542e3 | 2011-03-31 18:44:04 +0000 | [diff] [blame] | 11572 | // A8.6.391 VST1 (multiple single elements) | 
|  | 11573 | // Vector Store (multiple single elements) stores elements to memory from one, two, three, or four regsiters, without | 
|  | 11574 | // interleaving.  Every element of each register is stored. | 
|  | 11575 | bool | 
|  | 11576 | EmulateInstructionARM::EmulateVST1Multiple (const uint32_t opcode, ARMEncoding encoding) | 
|  | 11577 | { | 
|  | 11578 | #if 0 | 
|  | 11579 | if ConditionPassed() then | 
|  | 11580 | EncodingSpecificOperations(); CheckAdvSIMDEnabled(); NullCheckIfThumbEE(n); | 
|  | 11581 | address = R[n]; if (address MOD alignment) != 0 then GenerateAlignmentException(); | 
|  | 11582 | if wback then R[n] = R[n] + (if register_index then R[m] else 8*regs); | 
|  | 11583 | for r = 0 to regs-1 | 
|  | 11584 | for e = 0 to elements-1 | 
|  | 11585 | MemU[address,ebytes] = Elem[D[d+r],e,esize]; | 
|  | 11586 | address = address + ebytes; | 
|  | 11587 | #endif | 
|  | 11588 |  | 
|  | 11589 | bool success = false; | 
|  | 11590 |  | 
|  | 11591 | if (ConditionPassed (opcode)) | 
|  | 11592 | { | 
|  | 11593 | uint32_t regs; | 
|  | 11594 | uint32_t alignment; | 
|  | 11595 | uint32_t ebytes; | 
|  | 11596 | uint32_t esize; | 
|  | 11597 | uint32_t elements; | 
|  | 11598 | uint32_t d; | 
|  | 11599 | uint32_t n; | 
|  | 11600 | uint32_t m; | 
|  | 11601 | bool wback; | 
|  | 11602 | bool register_index; | 
|  | 11603 |  | 
|  | 11604 | switch (encoding) | 
|  | 11605 | { | 
|  | 11606 | case eEncodingT1: | 
|  | 11607 | case eEncodingA1: | 
|  | 11608 | { | 
|  | 11609 | uint32_t type = Bits32 (opcode, 11, 8); | 
|  | 11610 | uint32_t align = Bits32 (opcode, 5, 4); | 
|  | 11611 |  | 
|  | 11612 | // case type of | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 11613 | if (type == 7)    // when Ô0111Õ | 
| Caroline Tice | 1e542e3 | 2011-03-31 18:44:04 +0000 | [diff] [blame] | 11614 | { | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 11615 | // regs = 1; if align<1> == Ô1Õ then UNDEFINED; | 
| Caroline Tice | 1e542e3 | 2011-03-31 18:44:04 +0000 | [diff] [blame] | 11616 | regs = 1; | 
|  | 11617 | if (BitIsSet (align, 1)) | 
|  | 11618 | return false; | 
|  | 11619 | } | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 11620 | else if (type == 10) // when Ô1010Õ | 
| Caroline Tice | 1e542e3 | 2011-03-31 18:44:04 +0000 | [diff] [blame] | 11621 | { | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 11622 | // regs = 2; if align == Ô11Õ then UNDEFINED; | 
| Caroline Tice | 1e542e3 | 2011-03-31 18:44:04 +0000 | [diff] [blame] | 11623 | regs = 2; | 
|  | 11624 | if (align == 3) | 
|  | 11625 | return false; | 
|  | 11626 | } | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 11627 | else if (type == 6) // when Ô0110Õ | 
| Caroline Tice | 1e542e3 | 2011-03-31 18:44:04 +0000 | [diff] [blame] | 11628 | { | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 11629 | // regs = 3; if align<1> == Ô1Õ then UNDEFINED; | 
| Caroline Tice | 1e542e3 | 2011-03-31 18:44:04 +0000 | [diff] [blame] | 11630 | regs = 3; | 
|  | 11631 | if (BitIsSet (align, 1)) | 
|  | 11632 | return false; | 
|  | 11633 | } | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 11634 | else if (type == 2) // when Ô0010Õ | 
| Caroline Tice | 1e542e3 | 2011-03-31 18:44:04 +0000 | [diff] [blame] | 11635 | // regs = 4; | 
|  | 11636 | regs = 4; | 
|  | 11637 | else // otherwise | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 11638 | // SEE ÒRelated encodingsÓ; | 
| Caroline Tice | 1e542e3 | 2011-03-31 18:44:04 +0000 | [diff] [blame] | 11639 | return false; | 
|  | 11640 |  | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 11641 | // alignment = if align == Ô00Õ then 1 else 4 << UInt(align); | 
| Caroline Tice | 1e542e3 | 2011-03-31 18:44:04 +0000 | [diff] [blame] | 11642 | if (align == 0) | 
| Johnny Chen | a1c7e46 | 2011-08-12 17:59:58 +0000 | [diff] [blame] | 11643 | alignment = 1; | 
| Caroline Tice | 1e542e3 | 2011-03-31 18:44:04 +0000 | [diff] [blame] | 11644 | else | 
|  | 11645 | alignment = 4 << align; | 
|  | 11646 |  | 
|  | 11647 | // ebytes = 1 << UInt(size); esize = 8 * ebytes; elements = 8 DIV ebytes; | 
|  | 11648 | ebytes = 1 << Bits32 (opcode,7, 6); | 
|  | 11649 | esize = 8 * ebytes; | 
|  | 11650 | elements = 8 / ebytes; | 
|  | 11651 |  | 
|  | 11652 | // d = UInt(D:Vd); n = UInt(Rn); m = UInt(Rm); | 
|  | 11653 | d = (Bit32 (opcode, 22) << 4) | Bits32 (opcode, 15, 12); | 
|  | 11654 | n = Bits32 (opcode, 19, 16); | 
|  | 11655 | m = Bits32 (opcode, 3, 0); | 
|  | 11656 |  | 
|  | 11657 | // wback = (m != 15); register_index = (m != 15 && m != 13); | 
|  | 11658 | wback = (m != 15); | 
|  | 11659 | register_index = ((m != 15) && (m != 13)); | 
|  | 11660 |  | 
|  | 11661 | // if d+regs > 32 then UNPREDICTABLE; if n == 15 then UNPREDICTABLE; | 
|  | 11662 | if ((d + regs) > 32) | 
|  | 11663 | return false; | 
|  | 11664 |  | 
|  | 11665 | if (n == 15) | 
|  | 11666 | return false; | 
|  | 11667 |  | 
|  | 11668 | } | 
|  | 11669 | break; | 
|  | 11670 |  | 
|  | 11671 | default: | 
|  | 11672 | return false; | 
|  | 11673 | } | 
|  | 11674 |  | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 11675 | RegisterInfo base_reg; | 
|  | 11676 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
| Caroline Tice | 1e542e3 | 2011-03-31 18:44:04 +0000 | [diff] [blame] | 11677 |  | 
|  | 11678 | uint32_t Rn = ReadCoreReg (n, &success); | 
|  | 11679 | if (!success) | 
|  | 11680 | return false; | 
|  | 11681 |  | 
|  | 11682 | // address = R[n]; if (address MOD alignment) != 0 then GenerateAlignmentException(); | 
|  | 11683 | addr_t address = Rn; | 
|  | 11684 | if ((address % alignment) != 0) | 
|  | 11685 | return false; | 
|  | 11686 |  | 
|  | 11687 | EmulateInstruction::Context context; | 
|  | 11688 | // if wback then R[n] = R[n] + (if register_index then R[m] else 8*regs); | 
|  | 11689 | if (wback) | 
|  | 11690 | { | 
|  | 11691 | uint32_t Rm = ReadCoreReg (m, &success); | 
|  | 11692 | if (!success) | 
|  | 11693 | return false; | 
|  | 11694 |  | 
|  | 11695 | uint32_t offset; | 
|  | 11696 | if (register_index) | 
|  | 11697 | offset = Rm; | 
|  | 11698 | else | 
|  | 11699 | offset = 8 * regs; | 
|  | 11700 |  | 
|  | 11701 | context.type = eContextAdjustBaseRegister; | 
|  | 11702 | context.SetRegisterPlusOffset (base_reg, offset); | 
|  | 11703 |  | 
|  | 11704 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, Rn + offset)) | 
|  | 11705 | return false; | 
|  | 11706 | } | 
|  | 11707 |  | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 11708 | RegisterInfo data_reg; | 
| Caroline Tice | 1e542e3 | 2011-03-31 18:44:04 +0000 | [diff] [blame] | 11709 | context.type = eContextRegisterStore; | 
| Caroline Tice | 1e542e3 | 2011-03-31 18:44:04 +0000 | [diff] [blame] | 11710 | // for r = 0 to regs-1 | 
|  | 11711 | for (int r = 0; r < regs; ++r) | 
|  | 11712 | { | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 11713 | GetRegisterInfo (eRegisterKindDWARF, dwarf_d0 + d + r, data_reg); | 
| Caroline Tice | 1e542e3 | 2011-03-31 18:44:04 +0000 | [diff] [blame] | 11714 | uint64_t register_data = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_d0 + d + r, 0, &success); | 
|  | 11715 | if (!success) | 
|  | 11716 | return false; | 
|  | 11717 |  | 
|  | 11718 | // for e = 0 to elements-1 | 
|  | 11719 | for (int e = 0; e < elements; ++e) | 
|  | 11720 | { | 
|  | 11721 | // MemU[address,ebytes] = Elem[D[d+r],e,esize]; | 
| Caroline Tice | 7b88094 | 2011-03-31 19:17:12 +0000 | [diff] [blame] | 11722 | uint64_t word = Bits64 (register_data, ((e + 1) * esize) - 1, e * esize); | 
| Caroline Tice | 1e542e3 | 2011-03-31 18:44:04 +0000 | [diff] [blame] | 11723 |  | 
|  | 11724 | context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, address - Rn); | 
|  | 11725 | if (!MemUWrite (context, address, word, ebytes)) | 
|  | 11726 | return false; | 
|  | 11727 |  | 
|  | 11728 | // address = address + ebytes; | 
|  | 11729 | address = address + ebytes; | 
|  | 11730 | } | 
|  | 11731 | } | 
|  | 11732 | } | 
|  | 11733 | return true; | 
|  | 11734 | } | 
|  | 11735 |  | 
| Caroline Tice | 7b88094 | 2011-03-31 19:17:12 +0000 | [diff] [blame] | 11736 | // A8.6.392 VST1 (single element from one lane) | 
|  | 11737 | // This instruction stores one element to memory from one element of a register. | 
|  | 11738 | bool | 
|  | 11739 | EmulateInstructionARM::EmulateVST1Single (const uint32_t opcode, ARMEncoding encoding) | 
|  | 11740 | { | 
|  | 11741 | #if 0 | 
|  | 11742 | if ConditionPassed() then | 
|  | 11743 | EncodingSpecificOperations(); CheckAdvSIMDEnabled(); NullCheckIfThumbEE(n); | 
|  | 11744 | address = R[n]; if (address MOD alignment) != 0 then GenerateAlignmentException(); | 
|  | 11745 | if wback then R[n] = R[n] + (if register_index then R[m] else ebytes); | 
|  | 11746 | MemU[address,ebytes] = Elem[D[d],index,esize]; | 
|  | 11747 | #endif | 
|  | 11748 |  | 
|  | 11749 | bool success = false; | 
|  | 11750 |  | 
|  | 11751 | if (ConditionPassed (opcode)) | 
|  | 11752 | { | 
|  | 11753 | uint32_t ebytes; | 
|  | 11754 | uint32_t esize; | 
|  | 11755 | uint32_t index; | 
|  | 11756 | uint32_t alignment; | 
|  | 11757 | uint32_t d; | 
|  | 11758 | uint32_t n; | 
|  | 11759 | uint32_t m; | 
|  | 11760 | bool wback; | 
|  | 11761 | bool register_index; | 
|  | 11762 |  | 
|  | 11763 | switch (encoding) | 
|  | 11764 | { | 
|  | 11765 | case eEncodingT1: | 
|  | 11766 | case eEncodingA1: | 
|  | 11767 | { | 
|  | 11768 | uint32_t size = Bits32 (opcode, 11, 10); | 
|  | 11769 | uint32_t index_align = Bits32 (opcode, 7, 4); | 
|  | 11770 |  | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 11771 | // if size == Ô11Õ then UNDEFINED; | 
| Caroline Tice | 7b88094 | 2011-03-31 19:17:12 +0000 | [diff] [blame] | 11772 | if (size == 3) | 
|  | 11773 | return false; | 
|  | 11774 |  | 
|  | 11775 | // case size of | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 11776 | if (size == 0) // when Ô00Õ | 
| Caroline Tice | 7b88094 | 2011-03-31 19:17:12 +0000 | [diff] [blame] | 11777 | { | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 11778 | // if index_align<0> != Ô0Õ then UNDEFINED; | 
| Caroline Tice | 7b88094 | 2011-03-31 19:17:12 +0000 | [diff] [blame] | 11779 | if (BitIsClear (index_align, 0)) | 
|  | 11780 | return false; | 
|  | 11781 | // ebytes = 1; esize = 8; index = UInt(index_align<3:1>); alignment = 1; | 
|  | 11782 | ebytes = 1; | 
|  | 11783 | esize = 8; | 
|  | 11784 | index = Bits32 (index_align, 3, 1); | 
|  | 11785 | alignment = 1; | 
|  | 11786 | } | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 11787 | else if (size == 1) // when Ô01Õ | 
| Caroline Tice | 7b88094 | 2011-03-31 19:17:12 +0000 | [diff] [blame] | 11788 | { | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 11789 | // if index_align<1> != Ô0Õ then UNDEFINED; | 
| Caroline Tice | 7b88094 | 2011-03-31 19:17:12 +0000 | [diff] [blame] | 11790 | if (BitIsClear (index_align, 1)) | 
|  | 11791 | return false; | 
|  | 11792 |  | 
|  | 11793 | // ebytes = 2; esize = 16; index = UInt(index_align<3:2>); | 
|  | 11794 | ebytes = 2; | 
|  | 11795 | esize = 16; | 
|  | 11796 | index = Bits32 (index_align, 3, 2); | 
|  | 11797 |  | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 11798 | // alignment = if index_align<0> == Ô0Õ then 1 else 2; | 
| Caroline Tice | 7b88094 | 2011-03-31 19:17:12 +0000 | [diff] [blame] | 11799 | if (BitIsClear (index_align, 0)) | 
|  | 11800 | alignment = 1; | 
|  | 11801 | else | 
|  | 11802 | alignment = 2; | 
|  | 11803 | } | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 11804 | else if (size == 2) // when Ô10Õ | 
| Caroline Tice | 7b88094 | 2011-03-31 19:17:12 +0000 | [diff] [blame] | 11805 | { | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 11806 | // if index_align<2> != Ô0Õ then UNDEFINED; | 
| Caroline Tice | 7b88094 | 2011-03-31 19:17:12 +0000 | [diff] [blame] | 11807 | if (BitIsClear (index_align, 2)) | 
|  | 11808 | return false; | 
|  | 11809 |  | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 11810 | // if index_align<1:0> != Ô00Õ && index_align<1:0> != Ô11Õ then UNDEFINED; | 
| Caroline Tice | 7b88094 | 2011-03-31 19:17:12 +0000 | [diff] [blame] | 11811 | if ((Bits32 (index_align, 1, 0) != 0) && (Bits32 (index_align, 1, 0) != 3)) | 
|  | 11812 | return false; | 
|  | 11813 |  | 
|  | 11814 | // ebytes = 4; esize = 32; index = UInt(index_align<3>); | 
|  | 11815 | ebytes = 4; | 
|  | 11816 | esize = 32; | 
|  | 11817 | index = Bit32 (index_align, 3); | 
|  | 11818 |  | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 11819 | // alignment = if index_align<1:0> == Ô00Õ then 1 else 4; | 
| Caroline Tice | 7b88094 | 2011-03-31 19:17:12 +0000 | [diff] [blame] | 11820 | if (Bits32 (index_align, 1, 0) == 0) | 
|  | 11821 | alignment = 1; | 
|  | 11822 | else | 
|  | 11823 | alignment = 4; | 
|  | 11824 | } | 
|  | 11825 | // d = UInt(D:Vd); n = UInt(Rn); m = UInt(Rm); | 
|  | 11826 | d = (Bit32 (opcode, 22) << 4) | Bits32 (opcode, 15, 12); | 
|  | 11827 | n = Bits32 (opcode, 19, 16); | 
|  | 11828 | m = Bits32 (opcode, 3, 0); | 
|  | 11829 |  | 
|  | 11830 | // wback = (m != 15); register_index = (m != 15 && m != 13);  if n == 15 then UNPREDICTABLE; | 
|  | 11831 | wback = (m != 15); | 
|  | 11832 | register_index = ((m != 15) && (m != 13)); | 
|  | 11833 |  | 
|  | 11834 | if (n == 15) | 
|  | 11835 | return false; | 
|  | 11836 | } | 
|  | 11837 | break; | 
|  | 11838 |  | 
|  | 11839 | default: | 
|  | 11840 | return false; | 
|  | 11841 | } | 
|  | 11842 |  | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 11843 | RegisterInfo base_reg; | 
|  | 11844 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
| Caroline Tice | 7b88094 | 2011-03-31 19:17:12 +0000 | [diff] [blame] | 11845 |  | 
|  | 11846 | uint32_t Rn = ReadCoreReg (n, &success); | 
|  | 11847 | if (!success) | 
|  | 11848 | return false; | 
|  | 11849 |  | 
|  | 11850 | // address = R[n]; if (address MOD alignment) != 0 then GenerateAlignmentException(); | 
|  | 11851 | addr_t address = Rn; | 
|  | 11852 | if ((address % alignment) != 0) | 
|  | 11853 | return false; | 
|  | 11854 |  | 
|  | 11855 | EmulateInstruction::Context context; | 
|  | 11856 | // if wback then R[n] = R[n] + (if register_index then R[m] else ebytes); | 
|  | 11857 | if (wback) | 
|  | 11858 | { | 
|  | 11859 | uint32_t Rm = ReadCoreReg (m, &success); | 
|  | 11860 | if (!success) | 
|  | 11861 | return false; | 
|  | 11862 |  | 
|  | 11863 | uint32_t offset; | 
|  | 11864 | if (register_index) | 
|  | 11865 | offset = Rm; | 
|  | 11866 | else | 
|  | 11867 | offset = ebytes; | 
|  | 11868 |  | 
|  | 11869 | context.type = eContextAdjustBaseRegister; | 
|  | 11870 | context.SetRegisterPlusOffset (base_reg, offset); | 
|  | 11871 |  | 
|  | 11872 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, Rn + offset)) | 
|  | 11873 | return false; | 
|  | 11874 | } | 
|  | 11875 |  | 
|  | 11876 | // MemU[address,ebytes] = Elem[D[d],index,esize]; | 
|  | 11877 | uint64_t register_data = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_d0 + d, 0, &success); | 
|  | 11878 | if (!success) | 
|  | 11879 | return false; | 
|  | 11880 |  | 
|  | 11881 | uint64_t word = Bits64 (register_data, ((index + 1) * esize) - 1,  index * esize); | 
|  | 11882 |  | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 11883 | RegisterInfo data_reg; | 
|  | 11884 | GetRegisterInfo (eRegisterKindDWARF, dwarf_d0 + d, data_reg); | 
| Caroline Tice | 7b88094 | 2011-03-31 19:17:12 +0000 | [diff] [blame] | 11885 | context.type = eContextRegisterStore; | 
|  | 11886 | context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, address - Rn); | 
|  | 11887 |  | 
|  | 11888 | if (!MemUWrite (context, address, word, ebytes)) | 
|  | 11889 | return false; | 
|  | 11890 | } | 
|  | 11891 | return true; | 
|  | 11892 | } | 
|  | 11893 |  | 
| Caroline Tice | 8d24b4a | 2011-03-31 21:31:50 +0000 | [diff] [blame] | 11894 | // A8.6.309 VLD1 (single element to all lanes) | 
|  | 11895 | // This instruction loads one element from memory into every element of one or two vectors. | 
| Caroline Tice | 93767b8 | 2011-03-31 21:15:29 +0000 | [diff] [blame] | 11896 | bool | 
| Caroline Tice | 8d24b4a | 2011-03-31 21:31:50 +0000 | [diff] [blame] | 11897 | EmulateInstructionARM::EmulateVLD1SingleAll (const uint32_t opcode, const ARMEncoding encoding) | 
| Caroline Tice | 93767b8 | 2011-03-31 21:15:29 +0000 | [diff] [blame] | 11898 | { | 
|  | 11899 | #if 0 | 
|  | 11900 | if ConditionPassed() then | 
|  | 11901 | EncodingSpecificOperations(); CheckAdvSIMDEnabled(); NullCheckIfThumbEE(n); | 
|  | 11902 | address = R[n]; if (address MOD alignment) != 0 then GenerateAlignmentException(); | 
|  | 11903 | if wback then R[n] = R[n] + (if register_index then R[m] else ebytes); | 
|  | 11904 | replicated_element = Replicate(MemU[address,ebytes], elements); | 
|  | 11905 | for r = 0 to regs-1 | 
|  | 11906 | D[d+r] = replicated_element; | 
|  | 11907 | #endif | 
|  | 11908 |  | 
|  | 11909 | bool success = false; | 
|  | 11910 |  | 
|  | 11911 | if (ConditionPassed (opcode)) | 
|  | 11912 | { | 
|  | 11913 | uint32_t ebytes; | 
|  | 11914 | uint32_t elements; | 
|  | 11915 | uint32_t regs; | 
|  | 11916 | uint32_t alignment; | 
|  | 11917 | uint32_t d; | 
|  | 11918 | uint32_t n; | 
|  | 11919 | uint32_t m; | 
|  | 11920 | bool wback; | 
|  | 11921 | bool register_index; | 
|  | 11922 |  | 
|  | 11923 | switch (encoding) | 
|  | 11924 | { | 
|  | 11925 | case eEncodingT1: | 
|  | 11926 | case eEncodingA1: | 
|  | 11927 | { | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 11928 | //if size == Ô11Õ || (size == Ô00Õ && a == Ô1Õ) then UNDEFINED; | 
| Caroline Tice | 93767b8 | 2011-03-31 21:15:29 +0000 | [diff] [blame] | 11929 | uint32_t size = Bits32 (opcode, 7, 6); | 
|  | 11930 | if ((size == 3) || ((size == 0) && BitIsSet (opcode, 4))) | 
|  | 11931 | return false; | 
|  | 11932 |  | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 11933 | //ebytes = 1 << UInt(size); elements = 8 DIV ebytes; regs = if T == Ô0Õ then 1 else 2; | 
| Caroline Tice | 93767b8 | 2011-03-31 21:15:29 +0000 | [diff] [blame] | 11934 | ebytes = 1 << size; | 
|  | 11935 | elements = 8 / ebytes; | 
|  | 11936 | if (BitIsClear (opcode, 5)) | 
|  | 11937 | regs = 1; | 
|  | 11938 | else | 
|  | 11939 | regs = 2; | 
|  | 11940 |  | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 11941 | //alignment = if a == Ô0Õ then 1 else ebytes; | 
| Caroline Tice | 93767b8 | 2011-03-31 21:15:29 +0000 | [diff] [blame] | 11942 | if (BitIsClear (opcode, 4)) | 
|  | 11943 | alignment = 1; | 
|  | 11944 | else | 
|  | 11945 | alignment = ebytes; | 
|  | 11946 |  | 
|  | 11947 | //d = UInt(D:Vd); n = UInt(Rn); m = UInt(Rm); | 
|  | 11948 | d = (Bit32 (opcode, 22) << 4) | Bits32 (opcode, 15, 12); | 
|  | 11949 | n = Bits32 (opcode, 19, 16); | 
|  | 11950 | m = Bits32 (opcode, 3, 0); | 
|  | 11951 |  | 
|  | 11952 | //wback = (m != 15); register_index = (m != 15 && m != 13); | 
|  | 11953 | wback = (m != 15); | 
|  | 11954 | register_index = ((m != 15) && (m != 13)); | 
|  | 11955 |  | 
|  | 11956 | //if d+regs > 32 then UNPREDICTABLE; if n == 15 then UNPREDICTABLE; | 
|  | 11957 | if ((d + regs) > 32) | 
|  | 11958 | return false; | 
|  | 11959 |  | 
|  | 11960 | if (n == 15) | 
|  | 11961 | return false; | 
|  | 11962 | } | 
| Johnny Chen | 6ac9e54 | 2011-08-16 01:16:02 +0000 | [diff] [blame^] | 11963 | break; | 
| Caroline Tice | 93767b8 | 2011-03-31 21:15:29 +0000 | [diff] [blame] | 11964 |  | 
|  | 11965 | default: | 
| Johnny Chen | 6ac9e54 | 2011-08-16 01:16:02 +0000 | [diff] [blame^] | 11966 | return false; | 
| Caroline Tice | 93767b8 | 2011-03-31 21:15:29 +0000 | [diff] [blame] | 11967 | } | 
|  | 11968 |  | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 11969 | RegisterInfo base_reg; | 
|  | 11970 | GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg); | 
| Caroline Tice | 93767b8 | 2011-03-31 21:15:29 +0000 | [diff] [blame] | 11971 |  | 
|  | 11972 | uint32_t Rn = ReadCoreReg (n, &success); | 
|  | 11973 | if (!success) | 
|  | 11974 | return false; | 
|  | 11975 |  | 
|  | 11976 | // address = R[n]; if (address MOD alignment) != 0 then GenerateAlignmentException(); | 
|  | 11977 | addr_t address = Rn; | 
|  | 11978 | if ((address % alignment) != 0) | 
|  | 11979 | return false; | 
|  | 11980 |  | 
|  | 11981 | EmulateInstruction::Context context; | 
|  | 11982 | // if wback then R[n] = R[n] + (if register_index then R[m] else ebytes); | 
|  | 11983 | if (wback) | 
|  | 11984 | { | 
|  | 11985 | uint32_t Rm = ReadCoreReg (m, &success); | 
|  | 11986 | if (!success) | 
|  | 11987 | return false; | 
|  | 11988 |  | 
|  | 11989 | uint32_t offset; | 
|  | 11990 | if (register_index) | 
|  | 11991 | offset = Rm; | 
|  | 11992 | else | 
|  | 11993 | offset = ebytes; | 
|  | 11994 |  | 
|  | 11995 | context.type = eContextAdjustBaseRegister; | 
|  | 11996 | context.SetRegisterPlusOffset (base_reg, offset); | 
|  | 11997 |  | 
|  | 11998 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, Rn + offset)) | 
|  | 11999 | return false; | 
|  | 12000 | } | 
|  | 12001 |  | 
|  | 12002 | // replicated_element = Replicate(MemU[address,ebytes], elements); | 
|  | 12003 |  | 
|  | 12004 | context.type = eContextRegisterLoad; | 
|  | 12005 | uint64_t word = MemURead (context, address, ebytes, 0, &success); | 
|  | 12006 | if (!success) | 
|  | 12007 | return false; | 
|  | 12008 |  | 
| Johnny Chen | 65f39ed | 2011-08-12 01:10:45 +0000 | [diff] [blame] | 12009 | uint64_t replicated_element = 0; | 
| Caroline Tice | 93767b8 | 2011-03-31 21:15:29 +0000 | [diff] [blame] | 12010 | uint32_t esize = ebytes * 8; | 
|  | 12011 | for (int e = 0; e < elements; ++e) | 
|  | 12012 | replicated_element = (replicated_element << esize) | Bits64 (word, esize - 1, 0); | 
|  | 12013 |  | 
|  | 12014 | // for r = 0 to regs-1 | 
|  | 12015 | for (int r = 0; r < regs; ++r) | 
|  | 12016 | { | 
|  | 12017 | // D[d+r] = replicated_element; | 
|  | 12018 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_d0 + d + r, replicated_element)) | 
|  | 12019 | return false; | 
|  | 12020 | } | 
|  | 12021 | } | 
|  | 12022 | return true; | 
|  | 12023 | } | 
|  | 12024 |  | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 12025 | // B6.2.13 SUBS PC, LR and related instructions | 
|  | 12026 | //The SUBS PC, LR, #<const? instruction provides an exception return without the use of the stack.  It subtracts the | 
|  | 12027 | // immediate constant from the LR, branches to the resulting address, and also copies the SPSR to the CPSR. | 
|  | 12028 | bool | 
|  | 12029 | EmulateInstructionARM::EmulateSUBSPcLrEtc (const uint32_t opcode, const ARMEncoding encoding) | 
|  | 12030 | { | 
|  | 12031 | #if 0 | 
|  | 12032 | if ConditionPassed() then | 
|  | 12033 | EncodingSpecificOperations(); | 
|  | 12034 | if CurrentInstrSet() == InstrSet_ThumbEE then | 
|  | 12035 | UNPREDICTABLE; | 
|  | 12036 | operand2 = if register_form then Shift(R[m], shift_t, shift_n, APSR.C) else imm32; | 
|  | 12037 | case opcode of | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 12038 | when Ô0000Õ result = R[n] AND operand2; // AND | 
|  | 12039 | when Ô0001Õ result = R[n] EOR operand2; // EOR | 
|  | 12040 | when Ô0010Õ (result, -, -) = AddWithCarry(R[n], NOT(operand2), Ô1Õ); // SUB | 
|  | 12041 | when Ô0011Õ (result, -, -) = AddWithCarry(NOT(R[n]), operand2, Ô1Õ); // RSB | 
|  | 12042 | when Ô0100Õ (result, -, -) = AddWithCarry(R[n], operand2, Ô0Õ); // ADD | 
|  | 12043 | when Ô0101Õ (result, -, -) = AddWithCarry(R[n], operand2, APSR.c); // ADC | 
|  | 12044 | when Ô0110Õ (result, -, -) = AddWithCarry(R[n], NOT(operand2), APSR.C); // SBC | 
|  | 12045 | when Ô0111Õ (result, -, -) = AddWithCarry(NOT(R[n]), operand2, APSR.C); // RSC | 
|  | 12046 | when Ô1100Õ result = R[n] OR operand2; // ORR | 
|  | 12047 | when Ô1101Õ result = operand2; // MOV | 
|  | 12048 | when Ô1110Õ result = R[n] AND NOT(operand2); // BIC | 
|  | 12049 | when Ô1111Õ result = NOT(operand2); // MVN | 
|  | 12050 | CPSRWriteByInstr(SPSR[], Ô1111Õ, TRUE); | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 12051 | BranchWritePC(result); | 
|  | 12052 | #endif | 
|  | 12053 |  | 
|  | 12054 | bool success = false; | 
|  | 12055 |  | 
|  | 12056 | if (ConditionPassed (opcode)) | 
|  | 12057 | { | 
|  | 12058 | uint32_t n; | 
|  | 12059 | uint32_t m; | 
|  | 12060 | uint32_t imm32; | 
|  | 12061 | bool register_form; | 
|  | 12062 | ARM_ShifterType shift_t; | 
|  | 12063 | uint32_t shift_n; | 
|  | 12064 | uint32_t code; | 
|  | 12065 |  | 
|  | 12066 | switch (encoding) | 
|  | 12067 | { | 
|  | 12068 | case eEncodingT1: | 
|  | 12069 | // if CurrentInstrSet() == InstrSet_ThumbEE then UNPREDICTABLE | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 12070 | // n = 14; imm32 = ZeroExtend(imm8, 32); register_form = FALSE; opcode = Ô0010Õ; // = SUB | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 12071 | n = 14; | 
|  | 12072 | imm32 = Bits32 (opcode, 7, 0); | 
|  | 12073 | register_form = false; | 
|  | 12074 | code = 2; | 
|  | 12075 |  | 
|  | 12076 | // if InITBlock() && !LastInITBlock() then UNPREDICTABLE; | 
|  | 12077 | if (InITBlock() && !LastInITBlock()) | 
|  | 12078 | return false; | 
|  | 12079 |  | 
|  | 12080 | break; | 
|  | 12081 |  | 
|  | 12082 | case eEncodingA1: | 
|  | 12083 | // n = UInt(Rn); imm32 = ARMExpandImm(imm12); register_form = FALSE; | 
|  | 12084 | n = Bits32 (opcode, 19, 16); | 
|  | 12085 | imm32 = ARMExpandImm (opcode); | 
|  | 12086 | register_form = false; | 
|  | 12087 | code = Bits32 (opcode, 24, 21); | 
|  | 12088 |  | 
|  | 12089 | break; | 
|  | 12090 |  | 
|  | 12091 | case eEncodingA2: | 
|  | 12092 | // n = UInt(Rn); m = UInt(Rm); register_form = TRUE; | 
|  | 12093 | n = Bits32 (opcode, 19, 16); | 
|  | 12094 | m = Bits32 (opcode, 3, 0); | 
|  | 12095 | register_form = true; | 
|  | 12096 |  | 
|  | 12097 | // (shift_t, shift_n) = DecodeImmShift(type, imm5); | 
|  | 12098 | shift_n = DecodeImmShiftARM (opcode, shift_t); | 
|  | 12099 |  | 
|  | 12100 | break; | 
|  | 12101 |  | 
|  | 12102 | default: | 
|  | 12103 | return false; | 
|  | 12104 | } | 
|  | 12105 |  | 
|  | 12106 | // operand2 = if register_form then Shift(R[m], shift_t, shift_n, APSR.C) else imm32; | 
|  | 12107 | uint32_t operand2; | 
|  | 12108 | if (register_form) | 
|  | 12109 | { | 
|  | 12110 | uint32_t Rm = ReadCoreReg (m, &success); | 
|  | 12111 | if (!success) | 
|  | 12112 | return false; | 
|  | 12113 |  | 
| Johnny Chen | a4438a7 | 2011-06-02 22:50:51 +0000 | [diff] [blame] | 12114 | operand2 = Shift (Rm, shift_t, shift_n, APSR_C, &success); | 
|  | 12115 | if (!success) | 
|  | 12116 | return false; | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 12117 | } | 
|  | 12118 | else | 
|  | 12119 | { | 
|  | 12120 | operand2 = imm32; | 
|  | 12121 | } | 
|  | 12122 |  | 
|  | 12123 | uint32_t Rn = ReadCoreReg (n, &success); | 
|  | 12124 | if (!success) | 
|  | 12125 | return false; | 
|  | 12126 |  | 
|  | 12127 | AddWithCarryResult result; | 
|  | 12128 |  | 
|  | 12129 | // case opcode of | 
|  | 12130 | switch (code) | 
|  | 12131 | { | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 12132 | case 0: // when Ô0000Õ | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 12133 | // result = R[n] AND operand2; // AND | 
|  | 12134 | result.result = Rn & operand2; | 
|  | 12135 | break; | 
|  | 12136 |  | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 12137 | case 1: // when Ô0001Õ | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 12138 | // result = R[n] EOR operand2; // EOR | 
|  | 12139 | result.result = Rn ^ operand2; | 
|  | 12140 | break; | 
|  | 12141 |  | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 12142 | case 2: // when Ô0010Õ | 
|  | 12143 | // (result, -, -) = AddWithCarry(R[n], NOT(operand2), Ô1Õ); // SUB | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 12144 | result = AddWithCarry (Rn, ~(operand2), 1); | 
|  | 12145 | break; | 
|  | 12146 |  | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 12147 | case 3: // when Ô0011Õ | 
|  | 12148 | // (result, -, -) = AddWithCarry(NOT(R[n]), operand2, Ô1Õ); // RSB | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 12149 | result = AddWithCarry (~(Rn), operand2, 1); | 
|  | 12150 | break; | 
|  | 12151 |  | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 12152 | case 4: // when Ô0100Õ | 
|  | 12153 | // (result, -, -) = AddWithCarry(R[n], operand2, Ô0Õ); // ADD | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 12154 | result = AddWithCarry (Rn, operand2, 0); | 
|  | 12155 | break; | 
|  | 12156 |  | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 12157 | case 5: // when Ô0101Õ | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 12158 | // (result, -, -) = AddWithCarry(R[n], operand2, APSR.c); // ADC | 
|  | 12159 | result = AddWithCarry (Rn, operand2, APSR_C); | 
|  | 12160 | break; | 
|  | 12161 |  | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 12162 | case 6: // when Ô0110Õ | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 12163 | // (result, -, -) = AddWithCarry(R[n], NOT(operand2), APSR.C); // SBC | 
|  | 12164 | result = AddWithCarry (Rn, ~(operand2), APSR_C); | 
|  | 12165 | break; | 
|  | 12166 |  | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 12167 | case 7: // when Ô0111Õ | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 12168 | // (result, -, -) = AddWithCarry(NOT(R[n]), operand2, APSR.C); // RSC | 
|  | 12169 | result = AddWithCarry (~(Rn), operand2, APSR_C); | 
|  | 12170 | break; | 
|  | 12171 |  | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 12172 | case 10: // when Ô1100Õ | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 12173 | // result = R[n] OR operand2; // ORR | 
|  | 12174 | result.result = Rn | operand2; | 
|  | 12175 | break; | 
|  | 12176 |  | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 12177 | case 11: // when Ô1101Õ | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 12178 | // result = operand2; // MOV | 
|  | 12179 | result.result = operand2; | 
|  | 12180 | break; | 
|  | 12181 |  | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 12182 | case 12: // when Ô1110Õ | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 12183 | // result = R[n] AND NOT(operand2); // BIC | 
|  | 12184 | result.result = Rn & ~(operand2); | 
|  | 12185 | break; | 
|  | 12186 |  | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 12187 | case 15: // when Ô1111Õ | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 12188 | // result = NOT(operand2); // MVN | 
|  | 12189 | result.result = ~(operand2); | 
|  | 12190 | break; | 
|  | 12191 |  | 
|  | 12192 | default: | 
|  | 12193 | return false; | 
|  | 12194 | } | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 12195 | // CPSRWriteByInstr(SPSR[], Ô1111Õ, TRUE); | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 12196 |  | 
|  | 12197 | // For now, in emulation mode, we don't have access to the SPSR, so we will use the CPSR instead, and hope for | 
|  | 12198 | // the best. | 
|  | 12199 | uint32_t spsr = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_cpsr, 0, &success); | 
|  | 12200 | if (!success) | 
|  | 12201 | return false; | 
|  | 12202 |  | 
|  | 12203 | CPSRWriteByInstr (spsr, 15, true); | 
|  | 12204 |  | 
|  | 12205 | // BranchWritePC(result); | 
|  | 12206 | EmulateInstruction::Context context; | 
|  | 12207 | context.type = eContextAdjustPC; | 
|  | 12208 | context.SetImmediate (result.result); | 
|  | 12209 |  | 
|  | 12210 | BranchWritePC (context, result.result); | 
|  | 12211 | } | 
|  | 12212 | return true; | 
|  | 12213 | } | 
|  | 12214 |  | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 12215 | EmulateInstructionARM::ARMOpcode* | 
| Greg Clayton | 888a733 | 2011-04-26 04:39:08 +0000 | [diff] [blame] | 12216 | EmulateInstructionARM::GetARMOpcodeForInstruction (const uint32_t opcode, uint32_t arm_isa) | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 12217 | { | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 12218 | static ARMOpcode | 
|  | 12219 | g_arm_opcodes[] = | 
|  | 12220 | { | 
|  | 12221 | //---------------------------------------------------------------------- | 
|  | 12222 | // Prologue instructions | 
|  | 12223 | //---------------------------------------------------------------------- | 
| Johnny Chen | fdd179e | 2011-01-31 20:09:28 +0000 | [diff] [blame] | 12224 |  | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 12225 | // push register(s) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12226 | { 0x0fff0000, 0x092d0000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulatePUSH, "push <registers>" }, | 
|  | 12227 | { 0x0fff0fff, 0x052d0004, ARMvAll,       eEncodingA2, No_VFP, eSize32, &EmulateInstructionARM::EmulatePUSH, "push <register>" }, | 
| Johnny Chen | bcec3af | 2011-01-27 01:26:19 +0000 | [diff] [blame] | 12228 |  | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 12229 | // set r7 to point to a stack offset | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12230 | { 0x0ffff000, 0x028d7000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateADDRdSPImm, "add r7, sp, #<const>" }, | 
|  | 12231 | { 0x0ffff000, 0x024c7000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBR7IPImm, "sub r7, ip, #<const>"}, | 
| Johnny Chen | e7cf420 | 2011-02-10 18:13:23 +0000 | [diff] [blame] | 12232 | // copy the stack pointer to ip | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12233 | { 0x0fffffff, 0x01a0c00d, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateMOVRdSP, "mov ip, sp" }, | 
|  | 12234 | { 0x0ffff000, 0x028dc000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateADDRdSPImm, "add ip, sp, #<const>" }, | 
|  | 12235 | { 0x0ffff000, 0x024dc000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBIPSPImm, "sub ip, sp, #<const>"}, | 
| Johnny Chen | 4c0e0bc | 2011-01-25 22:45:28 +0000 | [diff] [blame] | 12236 |  | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 12237 | // adjust the stack pointer | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12238 | { 0x0ffff000, 0x024dd000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBSPImm, "sub sp, sp, #<const>"}, | 
|  | 12239 | { 0x0fef0010, 0x004d0000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBSPReg, "sub{s}<c> <Rd>, sp, <Rm>{,<shift>}" }, | 
| Johnny Chen | ce1ca77 | 2011-01-25 01:13:00 +0000 | [diff] [blame] | 12240 |  | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 12241 | // push one register | 
|  | 12242 | // if Rn == '1101' && imm12 == '000000000100' then SEE PUSH; | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12243 | { 0x0e5f0000, 0x040d0000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTRRtSP, "str Rt, [sp, #-imm12]!" }, | 
| Johnny Chen | 799dfd0 | 2011-01-26 23:14:33 +0000 | [diff] [blame] | 12244 |  | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 12245 | // vector push consecutive extension register(s) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12246 | { 0x0fbf0f00, 0x0d2d0b00, ARMV6T2_ABOVE, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateVPUSH, "vpush.64 <list>"}, | 
|  | 12247 | { 0x0fbf0f00, 0x0d2d0a00, ARMV6T2_ABOVE, eEncodingA2, No_VFP, eSize32, &EmulateInstructionARM::EmulateVPUSH, "vpush.32 <list>"}, | 
| Johnny Chen | ef85e91 | 2011-01-31 23:07:40 +0000 | [diff] [blame] | 12248 |  | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 12249 | //---------------------------------------------------------------------- | 
| Johnny Chen | 587a0a4 | 2011-02-01 18:35:28 +0000 | [diff] [blame] | 12250 | // Epilogue instructions | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 12251 | //---------------------------------------------------------------------- | 
| Johnny Chen | ef85e91 | 2011-01-31 23:07:40 +0000 | [diff] [blame] | 12252 |  | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12253 | { 0x0fff0000, 0x08bd0000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulatePOP, "pop <registers>"}, | 
|  | 12254 | { 0x0fff0fff, 0x049d0004, ARMvAll,       eEncodingA2, No_VFP, eSize32, &EmulateInstructionARM::EmulatePOP, "pop <register>"}, | 
|  | 12255 | { 0x0fbf0f00, 0x0cbd0b00, ARMV6T2_ABOVE, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateVPOP, "vpop.64 <list>"}, | 
|  | 12256 | { 0x0fbf0f00, 0x0cbd0a00, ARMV6T2_ABOVE, eEncodingA2, No_VFP, eSize32, &EmulateInstructionARM::EmulateVPOP, "vpop.32 <list>"}, | 
| Johnny Chen | b77be41 | 2011-02-04 00:40:18 +0000 | [diff] [blame] | 12257 |  | 
|  | 12258 | //---------------------------------------------------------------------- | 
|  | 12259 | // Supervisor Call (previously Software Interrupt) | 
|  | 12260 | //---------------------------------------------------------------------- | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12261 | { 0x0f000000, 0x0f000000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSVC, "svc #imm24"}, | 
| Johnny Chen | 3b620b3 | 2011-02-07 20:11:47 +0000 | [diff] [blame] | 12262 |  | 
|  | 12263 | //---------------------------------------------------------------------- | 
|  | 12264 | // Branch instructions | 
|  | 12265 | //---------------------------------------------------------------------- | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12266 | { 0x0f000000, 0x0a000000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateB, "b #imm24"}, | 
| Johnny Chen | 383d629 | 2011-02-11 21:23:32 +0000 | [diff] [blame] | 12267 | // To resolve ambiguity, "blx <label>" should come before "bl <label>". | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12268 | { 0xfe000000, 0xfa000000, ARMV5_ABOVE,   eEncodingA2, No_VFP, eSize32, &EmulateInstructionARM::EmulateBLXImmediate, "blx <label>"}, | 
|  | 12269 | { 0x0f000000, 0x0b000000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateBLXImmediate, "bl <label>"}, | 
|  | 12270 | { 0x0ffffff0, 0x012fff30, ARMV5_ABOVE,   eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateBLXRm, "blx <Rm>"}, | 
| Johnny Chen | ab3b351 | 2011-02-12 00:10:51 +0000 | [diff] [blame] | 12271 | // for example, "bx lr" | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12272 | { 0x0ffffff0, 0x012fff10, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateBXRm, "bx <Rm>"}, | 
| Johnny Chen | 59e6ab7 | 2011-02-24 21:01:20 +0000 | [diff] [blame] | 12273 | // bxj | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12274 | { 0x0ffffff0, 0x012fff20, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateBXJRm, "bxj <Rm>"}, | 
| Johnny Chen | b77be41 | 2011-02-04 00:40:18 +0000 | [diff] [blame] | 12275 |  | 
| Caroline Tice | b9f76c3 | 2011-02-08 22:24:38 +0000 | [diff] [blame] | 12276 | //---------------------------------------------------------------------- | 
| Johnny Chen | 28070c3 | 2011-02-12 01:27:26 +0000 | [diff] [blame] | 12277 | // Data-processing instructions | 
|  | 12278 | //---------------------------------------------------------------------- | 
| Johnny Chen | 157b959 | 2011-02-18 21:13:05 +0000 | [diff] [blame] | 12279 | // adc (immediate) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12280 | { 0x0fe00000, 0x02a00000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateADCImm, "adc{s}<c> <Rd>, <Rn>, #const"}, | 
| Johnny Chen | 157b959 | 2011-02-18 21:13:05 +0000 | [diff] [blame] | 12281 | // adc (register) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12282 | { 0x0fe00010, 0x00a00000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateADCReg, "adc{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"}, | 
| Johnny Chen | 8fa2059 | 2011-02-18 01:22:22 +0000 | [diff] [blame] | 12283 | // add (immediate) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12284 | { 0x0fe00000, 0x02800000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateADDImmARM, "add{s}<c> <Rd>, <Rn>, #const"}, | 
| Johnny Chen | 8fa2059 | 2011-02-18 01:22:22 +0000 | [diff] [blame] | 12285 | // add (register) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12286 | { 0x0fe00010, 0x00800000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateADDReg, "add{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"}, | 
| Caroline Tice | c08ed38 | 2011-03-29 23:03:16 +0000 | [diff] [blame] | 12287 | // add (register-shifted register) | 
| Caroline Tice | 0fe5a53 | 2011-04-08 23:33:06 +0000 | [diff] [blame] | 12288 | { 0x0fe00090, 0x00800010, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateADDRegShift, "add{s}<c> <Rd>, <Rn>, <Rm>, <type> <RS>"}, | 
| Johnny Chen | a695f95 | 2011-02-23 21:24:25 +0000 | [diff] [blame] | 12289 | // adr | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12290 | { 0x0fff0000, 0x028f0000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateADR, "add<c> <Rd>, PC, #<const>"}, | 
|  | 12291 | { 0x0fff0000, 0x024f0000, ARMvAll,       eEncodingA2, No_VFP, eSize32, &EmulateInstructionARM::EmulateADR, "sub<c> <Rd>, PC, #<const>"}, | 
| Johnny Chen | e97c0d5 | 2011-02-18 19:32:20 +0000 | [diff] [blame] | 12292 | // and (immediate) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12293 | { 0x0fe00000, 0x02000000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateANDImm, "and{s}<c> <Rd>, <Rn>, #const"}, | 
| Johnny Chen | e97c0d5 | 2011-02-18 19:32:20 +0000 | [diff] [blame] | 12294 | // and (register) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12295 | { 0x0fe00010, 0x00000000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateANDReg, "and{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"}, | 
| Johnny Chen | b9f02cf | 2011-02-24 01:15:17 +0000 | [diff] [blame] | 12296 | // bic (immediate) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12297 | { 0x0fe00000, 0x03c00000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateBICImm, "bic{s}<c> <Rd>, <Rn>, #const"}, | 
| Johnny Chen | b9f02cf | 2011-02-24 01:15:17 +0000 | [diff] [blame] | 12298 | // bic (register) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12299 | { 0x0fe00010, 0x01c00000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateBICReg, "bic{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"}, | 
| Johnny Chen | 2115b41 | 2011-02-21 23:42:44 +0000 | [diff] [blame] | 12300 | // eor (immediate) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12301 | { 0x0fe00000, 0x02200000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateEORImm, "eor{s}<c> <Rd>, <Rn>, #const"}, | 
| Johnny Chen | 2115b41 | 2011-02-21 23:42:44 +0000 | [diff] [blame] | 12302 | // eor (register) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12303 | { 0x0fe00010, 0x00200000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateEORReg, "eor{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"}, | 
| Johnny Chen | 7c5234d | 2011-02-18 23:41:11 +0000 | [diff] [blame] | 12304 | // orr (immediate) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12305 | { 0x0fe00000, 0x03800000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateORRImm, "orr{s}<c> <Rd>, <Rn>, #const"}, | 
| Johnny Chen | 7c5234d | 2011-02-18 23:41:11 +0000 | [diff] [blame] | 12306 | // orr (register) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12307 | { 0x0fe00010, 0x01800000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateORRReg, "orr{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"}, | 
| Johnny Chen | ed32e7c | 2011-02-22 23:42:58 +0000 | [diff] [blame] | 12308 | // rsb (immediate) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12309 | { 0x0fe00000, 0x02600000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateRSBImm, "rsb{s}<c> <Rd>, <Rn>, #<const>"}, | 
| Johnny Chen | ed32e7c | 2011-02-22 23:42:58 +0000 | [diff] [blame] | 12310 | // rsb (register) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12311 | { 0x0fe00010, 0x00600000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateRSBReg, "rsb{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"}, | 
| Johnny Chen | 90e607b | 2011-02-23 00:07:09 +0000 | [diff] [blame] | 12312 | // rsc (immediate) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12313 | { 0x0fe00000, 0x02e00000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateRSCImm, "rsc{s}<c> <Rd>, <Rn>, #<const>"}, | 
| Johnny Chen | 90e607b | 2011-02-23 00:07:09 +0000 | [diff] [blame] | 12314 | // rsc (register) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12315 | { 0x0fe00010, 0x00e00000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateRSCReg, "rsc{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"}, | 
| Johnny Chen | 9b38177 | 2011-02-23 01:01:21 +0000 | [diff] [blame] | 12316 | // sbc (immediate) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12317 | { 0x0fe00000, 0x02c00000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSBCImm, "sbc{s}<c> <Rd>, <Rn>, #<const>"}, | 
| Johnny Chen | 9b38177 | 2011-02-23 01:01:21 +0000 | [diff] [blame] | 12318 | // sbc (register) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12319 | { 0x0fe00010, 0x00c00000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSBCReg, "sbc{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"}, | 
| Johnny Chen | 15a7a6b | 2011-02-23 23:47:56 +0000 | [diff] [blame] | 12320 | // sub (immediate, ARM) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12321 | { 0x0fe00000, 0x02400000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBImmARM, "sub{s}<c> <Rd>, <Rn>, #<const>"}, | 
| Johnny Chen | c9e747f | 2011-02-23 01:55:07 +0000 | [diff] [blame] | 12322 | // sub (sp minus immediate) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12323 | { 0x0fef0000, 0x024d0000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBSPImm, "sub{s}<c> <Rd>, sp, #<const>"}, | 
| Caroline Tice | 4cccd53 | 2011-03-29 23:44:20 +0000 | [diff] [blame] | 12324 | // sub (register) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12325 | { 0x0fe00010, 0x00400000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBReg, "sub{s}<c> <Rd>, <Rn>, <Rm>{,<shift>}"}, | 
| Johnny Chen | 2115b41 | 2011-02-21 23:42:44 +0000 | [diff] [blame] | 12326 | // teq (immediate) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12327 | { 0x0ff0f000, 0x03300000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateTEQImm, "teq<c> <Rn>, #const"}, | 
| Johnny Chen | 2115b41 | 2011-02-21 23:42:44 +0000 | [diff] [blame] | 12328 | // teq (register) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12329 | { 0x0ff0f010, 0x01300000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateTEQReg, "teq<c> <Rn>, <Rm> {,<shift>}"}, | 
| Johnny Chen | de3cce3 | 2011-02-21 21:24:49 +0000 | [diff] [blame] | 12330 | // tst (immediate) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12331 | { 0x0ff0f000, 0x03100000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateTSTImm, "tst<c> <Rn>, #const"}, | 
| Johnny Chen | de3cce3 | 2011-02-21 21:24:49 +0000 | [diff] [blame] | 12332 | // tst (register) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12333 | { 0x0ff0f010, 0x01100000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateTSTReg, "tst<c> <Rn>, <Rm> {,<shift>}"}, | 
| Johnny Chen | de3cce3 | 2011-02-21 21:24:49 +0000 | [diff] [blame] | 12334 |  | 
| Caroline Tice | 89c6d58 | 2011-03-29 19:53:44 +0000 | [diff] [blame] | 12335 | // mov (immediate) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12336 | { 0x0fef0000, 0x03a00000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateMOVRdImm, "mov{s}<c> <Rd>, #<const>"}, | 
|  | 12337 | { 0x0ff00000, 0x03000000, ARMV6T2_ABOVE, eEncodingA2, No_VFP, eSize32, &EmulateInstructionARM::EmulateMOVRdImm, "movw<c> <Rd>, #<imm16>" }, | 
| Johnny Chen | 01d6157 | 2011-02-25 00:23:25 +0000 | [diff] [blame] | 12338 | // mov (register) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12339 | { 0x0fef0ff0, 0x01a00000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateMOVRdRm, "mov{s}<c> <Rd>, <Rm>"}, | 
| Johnny Chen | d642a6a | 2011-02-22 01:01:03 +0000 | [diff] [blame] | 12340 | // mvn (immediate) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12341 | { 0x0fef0000, 0x03e00000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateMVNImm, "mvn{s}<c> <Rd>, #<const>"}, | 
| Johnny Chen | d642a6a | 2011-02-22 01:01:03 +0000 | [diff] [blame] | 12342 | // mvn (register) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12343 | { 0x0fef0010, 0x01e00000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateMVNReg, "mvn{s}<c> <Rd>, <Rm> {,<shift>}"}, | 
| Johnny Chen | 3847dad | 2011-02-22 02:00:12 +0000 | [diff] [blame] | 12344 | // cmn (immediate) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12345 | { 0x0ff0f000, 0x03700000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateCMNImm, "cmn<c> <Rn>, #<const>"}, | 
| Johnny Chen | 3847dad | 2011-02-22 02:00:12 +0000 | [diff] [blame] | 12346 | // cmn (register) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12347 | { 0x0ff0f010, 0x01700000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateCMNReg, "cmn<c> <Rn>, <Rm> {,<shift>}"}, | 
| Johnny Chen | 34075cb | 2011-02-22 01:56:31 +0000 | [diff] [blame] | 12348 | // cmp (immediate) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12349 | { 0x0ff0f000, 0x03500000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateCMPImm, "cmp<c> <Rn>, #<const>"}, | 
| Johnny Chen | 34075cb | 2011-02-22 01:56:31 +0000 | [diff] [blame] | 12350 | // cmp (register) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12351 | { 0x0ff0f010, 0x01500000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateCMPReg, "cmp<c> <Rn>, <Rm> {,<shift>}"}, | 
| Johnny Chen | 82f16aa | 2011-02-15 20:10:55 +0000 | [diff] [blame] | 12352 | // asr (immediate) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12353 | { 0x0fef0070, 0x01a00040, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateASRImm, "asr{s}<c> <Rd>, <Rm>, #imm"}, | 
| Johnny Chen | 2ee35bc | 2011-02-16 19:27:43 +0000 | [diff] [blame] | 12354 | // asr (register) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12355 | { 0x0fef00f0, 0x01a00050, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateASRReg, "asr{s}<c> <Rd>, <Rn>, <Rm>"}, | 
| Johnny Chen | 2ee35bc | 2011-02-16 19:27:43 +0000 | [diff] [blame] | 12356 | // lsl (immediate) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12357 | { 0x0fef0070, 0x01a00000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLSLImm, "lsl{s}<c> <Rd>, <Rm>, #imm"}, | 
| Johnny Chen | 2ee35bc | 2011-02-16 19:27:43 +0000 | [diff] [blame] | 12358 | // lsl (register) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12359 | { 0x0fef00f0, 0x01a00010, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLSLReg, "lsl{s}<c> <Rd>, <Rn>, <Rm>"}, | 
| Johnny Chen | 2ee35bc | 2011-02-16 19:27:43 +0000 | [diff] [blame] | 12360 | // lsr (immediate) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12361 | { 0x0fef0070, 0x01a00020, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLSRImm, "lsr{s}<c> <Rd>, <Rm>, #imm"}, | 
| Johnny Chen | 2ee35bc | 2011-02-16 19:27:43 +0000 | [diff] [blame] | 12362 | // lsr (register) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12363 | { 0x0fef00f0, 0x01a00050, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLSRReg, "lsr{s}<c> <Rd>, <Rn>, <Rm>"}, | 
| Johnny Chen | eeab485 | 2011-02-16 22:14:44 +0000 | [diff] [blame] | 12364 | // rrx is a special case encoding of ror (immediate) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12365 | { 0x0fef0ff0, 0x01a00060, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateRRX, "rrx{s}<c> <Rd>, <Rm>"}, | 
| Johnny Chen | eeab485 | 2011-02-16 22:14:44 +0000 | [diff] [blame] | 12366 | // ror (immediate) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12367 | { 0x0fef0070, 0x01a00060, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateRORImm, "ror{s}<c> <Rd>, <Rm>, #imm"}, | 
| Johnny Chen | eeab485 | 2011-02-16 22:14:44 +0000 | [diff] [blame] | 12368 | // ror (register) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12369 | { 0x0fef00f0, 0x01a00070, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateRORReg, "ror{s}<c> <Rd>, <Rn>, <Rm>"}, | 
| Caroline Tice | 5c1e2ed | 2011-03-02 22:43:54 +0000 | [diff] [blame] | 12370 | // mul | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12371 | { 0x0fe000f0, 0x00000090, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateMUL, "mul{s}<c> <Rd>,<R>,<Rm>" }, | 
| Caroline Tice | 6b8d3b5 | 2011-04-19 23:30:03 +0000 | [diff] [blame] | 12372 |  | 
|  | 12373 | // subs pc, lr and related instructions | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 12374 | { 0x0e10f000, 0x0210f000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBSPcLrEtc, "<opc>S<c> PC,#<const> | <Rn>,#<const>" }, | 
|  | 12375 | { 0x0e10f010, 0x0010f000, ARMvAll,       eEncodingA2, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBSPcLrEtc, "<opc>S<c> PC,<Rn>,<Rm{,<shift>}" }, | 
| Johnny Chen | 28070c3 | 2011-02-12 01:27:26 +0000 | [diff] [blame] | 12376 |  | 
|  | 12377 | //---------------------------------------------------------------------- | 
| Caroline Tice | b9f76c3 | 2011-02-08 22:24:38 +0000 | [diff] [blame] | 12378 | // Load instructions | 
|  | 12379 | //---------------------------------------------------------------------- | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12380 | { 0x0fd00000, 0x08900000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDM, "ldm<c> <Rn>{!} <registers>" }, | 
|  | 12381 | { 0x0fd00000, 0x08100000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDMDA, "ldmda<c> <Rn>{!} <registers>" }, | 
|  | 12382 | { 0x0fd00000, 0x09100000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDMDB, "ldmdb<c> <Rn>{!} <registers>" }, | 
|  | 12383 | { 0x0fd00000, 0x09900000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDMIB, "ldmib<c> <Rn<{!} <registers>" }, | 
|  | 12384 | { 0x0e500000, 0x04100000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRImmediateARM, "ldr<c> <Rt> [<Rn> {#+/-<imm12>}]" }, | 
|  | 12385 | { 0x0e500010, 0x06100000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRRegister, "ldr<c> <Rt> [<Rn> +/-<Rm> {<shift>}] {!}" }, | 
|  | 12386 | { 0x0e5f0000, 0x045f0000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRBLiteral, "ldrb<c> <Rt>, [...]"}, | 
|  | 12387 | { 0xfe500010, 0x06500000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRBRegister, "ldrb<c> <Rt>, [<Rn>,+/-<Rm>{, <shift>}]{!}" }, | 
|  | 12388 | { 0x0e5f00f0, 0x005f00b0, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRHLiteral, "ldrh<c> <Rt>, <label>" }, | 
|  | 12389 | { 0x0e5000f0, 0x001000b0, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRHRegister, "ldrh<c> <Rt>,[<Rn>,+/-<Rm>]{!}"  }, | 
|  | 12390 | { 0x0e5000f0, 0x005000d0, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRSBImmediate, "ldrsb<c> <Rt>, [<Rn>{,#+/-<imm8>}]" }, | 
|  | 12391 | { 0x0e5f00f0, 0x005f00d0, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRSBLiteral, "ldrsb<c> <Rt> <label>" }, | 
|  | 12392 | { 0x0e5000f0, 0x001000d0, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRSBRegister, "ldrsb<c> <Rt>,[<Rn>,+/-<Rm>]{!}" }, | 
|  | 12393 | { 0x0e5000f0, 0x005000f0, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRSHImmediate, "ldrsh<c> <Rt>,[<Rn>{,#+/-<imm8>}]"}, | 
|  | 12394 | { 0x0e5f00f0, 0x005f00f0, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRSHLiteral, "ldrsh<c> <Rt>,<label>" }, | 
|  | 12395 | { 0x0e5000f0, 0x001000f0, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRSHRegister, "ldrsh<c> <Rt>,[<Rn>,+/-<Rm>]{!}" }, | 
|  | 12396 | { 0x0e5000f0, 0x004000d0, ARMV5TE_ABOVE, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRDImmediate, "ldrd<c> <Rt>, <Rt2>, [<Rn>,#+/-<imm8>]!"}, | 
|  | 12397 | { 0x0e500ff0, 0x000000d0, ARMV5TE_ABOVE, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRDRegister, "ldrd<c> <Rt>, <Rt2>, [<Rn>, +/-<Rm>]{!}"}, | 
| Caroline Tice | 9121b35 | 2011-03-31 16:41:19 +0000 | [diff] [blame] | 12398 | { 0x0e100f00, 0x0c100b00, ARMvAll,       eEncodingA1, VFPv2_ABOVE,  eSize32, &EmulateInstructionARM::EmulateVLDM, "vldm{mode}<c> <Rn>{!}, <list>"}, | 
|  | 12399 | { 0x0e100f00, 0x0c100a00, ARMvAll,       eEncodingA2, VFPv2v3,      eSize32, &EmulateInstructionARM::EmulateVLDM, "vldm{mode}<c> <Rn>{!}, <list>"}, | 
|  | 12400 | { 0x0f300f00, 0x0d100b00, ARMvAll,       eEncodingA1, VFPv2_ABOVE,  eSize32, &EmulateInstructionARM::EmulateVLDR, "vldr<c> <Dd>, [<Rn>{,#+/-<imm>}]"}, | 
|  | 12401 | { 0x0f300f00, 0x0d100a00, ARMvAll,       eEncodingA2, VFPv2v3,      eSize32, &EmulateInstructionARM::EmulateVLDR, "vldr<c> <Sd>, [<Rn>{,#+/-<imm>}]"}, | 
| Caroline Tice | b6281b1 | 2011-03-31 17:58:23 +0000 | [diff] [blame] | 12402 | { 0xffb00000, 0xf4200000, ARMvAll,       eEncodingA1, AdvancedSIMD, eSize32, &EmulateInstructionARM::EmulateVLD1Multiple, "vld1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>"}, | 
|  | 12403 | { 0xffb00300, 0xf4a00000, ARMvAll,       eEncodingA1, AdvancedSIMD, eSize32, &EmulateInstructionARM::EmulateVLD1Single, "vld1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>"}, | 
| Caroline Tice | 93767b8 | 2011-03-31 21:15:29 +0000 | [diff] [blame] | 12404 | { 0xffb00f00, 0xf4a00c00, ARMvAll,       eEncodingA1, AdvancedSIMD, eSize32, &EmulateInstructionARM::EmulateVLD1SingleAll, "vld1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>"}, | 
| Caroline Tice | fa17220 | 2011-02-11 22:49:54 +0000 | [diff] [blame] | 12405 |  | 
|  | 12406 | //---------------------------------------------------------------------- | 
|  | 12407 | // Store instructions | 
|  | 12408 | //---------------------------------------------------------------------- | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12409 | { 0x0fd00000, 0x08800000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTM, "stm<c> <Rn>{!} <registers>" }, | 
|  | 12410 | { 0x0fd00000, 0x08000000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTMDA, "stmda<c> <Rn>{!} <registers>" }, | 
|  | 12411 | { 0x0fd00000, 0x09000000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTMDB, "stmdb<c> <Rn>{!} <registers>" }, | 
|  | 12412 | { 0x0fd00000, 0x09800000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTMIB, "stmib<c> <Rn>{!} <registers>" }, | 
|  | 12413 | { 0x0e500010, 0x06000000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTRRegister, "str<c> <Rt> [<Rn> +/-<Rm> {<shift>}]{!}" }, | 
|  | 12414 | { 0x0e5000f0, 0x000000b0, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTRHRegister, "strh<c> <Rt>,[<Rn>,+/-<Rm>[{!}" }, | 
|  | 12415 | { 0x0ff00ff0, 0x01800f90, ARMV6_ABOVE,   eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTREX, "strex<c> <Rd>, <Rt>, [<Rn>]"}, | 
|  | 12416 | { 0x0e500000, 0x04400000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTRBImmARM, "strb<c> <Rt>,[<Rn>,#+/-<imm12>]!"}, | 
|  | 12417 | { 0x0e500000, 0x04000000, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTRImmARM, "str<c> <Rt>,[<Rn>,#+/-<imm12>]!"}, | 
| Caroline Tice | 0fe5a53 | 2011-04-08 23:33:06 +0000 | [diff] [blame] | 12418 | { 0x0e5000f0, 0x004000f0, ARMV5TE_ABOVE, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTRDImm, "strd<c> <Rt>, <Rt2>, [<Rn> #+/-<imm8>]!"}, | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12419 | { 0x0e500ff0, 0x000000f0, ARMV5TE_ABOVE, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTRDReg, "strd<c> <Rt>, <Rt2>, [<Rn>, +/-<Rm>]{!}"}, | 
| Caroline Tice | 1e542e3 | 2011-03-31 18:44:04 +0000 | [diff] [blame] | 12420 | { 0x0e100f00, 0x0c000b00, ARMvAll,       eEncodingA1, VFPv2_ABOVE,  eSize32, &EmulateInstructionARM::EmulateVSTM, "vstm{mode}<c> <Rn>{!} <list>"}, | 
|  | 12421 | { 0x0e100f00, 0x0c000a00, ARMvAll,       eEncodingA2, VFPv2v3,      eSize32, &EmulateInstructionARM::EmulateVSTM, "vstm{mode}<c> <Rn>{!} <list>"}, | 
|  | 12422 | { 0x0f300f00, 0x0d000b00, ARMvAll,       eEncodingA1, VFPv2_ABOVE,  eSize32, &EmulateInstructionARM::EmulateVSTR, "vstr<c> <Dd> [<Rn>{,#+/-<imm>}]"}, | 
|  | 12423 | { 0x0f300f00, 0x0d000a00, ARMvAll,       eEncodingA2, VFPv2v3,      eSize32, &EmulateInstructionARM::EmulateVSTR, "vstr<c> <Sd> [<Rn>{,#+/-<imm>}]"}, | 
|  | 12424 | { 0xffb00000, 0xf4000000, ARMvAll,       eEncodingA1, AdvancedSIMD, eSize32, &EmulateInstructionARM::EmulateVST1Multiple, "vst1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>"}, | 
| Caroline Tice | 7b88094 | 2011-03-31 19:17:12 +0000 | [diff] [blame] | 12425 | { 0xffb00300, 0xf4800000, ARMvAll,       eEncodingA1, AdvancedSIMD, eSize32, &EmulateInstructionARM::EmulateVST1Single, "vst1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>"}, | 
| Caroline Tice | 1511f50 | 2011-02-15 00:19:42 +0000 | [diff] [blame] | 12426 |  | 
| Caroline Tice | 6bf6516 | 2011-03-03 17:42:58 +0000 | [diff] [blame] | 12427 | //---------------------------------------------------------------------- | 
|  | 12428 | // Other instructions | 
|  | 12429 | //---------------------------------------------------------------------- | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12430 | { 0x0fff00f0, 0x06af00f0, ARMV6_ABOVE,  eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSXTB, "sxtb<c> <Rd>,<Rm>{,<rotation>}" }, | 
|  | 12431 | { 0x0fff00f0, 0x06bf0070, ARMV6_ABOVE,  eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSXTH, "sxth<c> <Rd>,<Rm>{,<rotation>}" }, | 
|  | 12432 | { 0x0fff00f0, 0x06ef0070, ARMV6_ABOVE,  eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateUXTB, "uxtb<c> <Rd>,<Rm>{,<rotation>}" }, | 
|  | 12433 | { 0x0fff00f0, 0x06ff0070, ARMV6_ABOVE,  eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateUXTH, "uxth<c> <Rd>,<Rm>{,<rotation>}" }, | 
|  | 12434 | { 0xfe500000, 0xf8100000, ARMV6_ABOVE,  eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateRFE, "rfe{<amode>} <Rn>{!}" } | 
| Caroline Tice | 6bf6516 | 2011-03-03 17:42:58 +0000 | [diff] [blame] | 12435 |  | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 12436 | }; | 
|  | 12437 | static const size_t k_num_arm_opcodes = sizeof(g_arm_opcodes)/sizeof(ARMOpcode); | 
|  | 12438 |  | 
|  | 12439 | for (size_t i=0; i<k_num_arm_opcodes; ++i) | 
|  | 12440 | { | 
| Greg Clayton | 888a733 | 2011-04-26 04:39:08 +0000 | [diff] [blame] | 12441 | if ((g_arm_opcodes[i].mask & opcode) == g_arm_opcodes[i].value && | 
|  | 12442 | (g_arm_opcodes[i].variants & arm_isa) != 0) | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 12443 | return &g_arm_opcodes[i]; | 
|  | 12444 | } | 
|  | 12445 | return NULL; | 
|  | 12446 | } | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 12447 |  | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 12448 |  | 
|  | 12449 | EmulateInstructionARM::ARMOpcode* | 
| Greg Clayton | 888a733 | 2011-04-26 04:39:08 +0000 | [diff] [blame] | 12450 | EmulateInstructionARM::GetThumbOpcodeForInstruction (const uint32_t opcode, uint32_t arm_isa) | 
| Johnny Chen | 347320d | 2011-01-24 23:40:59 +0000 | [diff] [blame] | 12451 | { | 
| Johnny Chen | fdd179e | 2011-01-31 20:09:28 +0000 | [diff] [blame] | 12452 |  | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 12453 | static ARMOpcode | 
|  | 12454 | g_thumb_opcodes[] = | 
|  | 12455 | { | 
|  | 12456 | //---------------------------------------------------------------------- | 
|  | 12457 | // Prologue instructions | 
|  | 12458 | //---------------------------------------------------------------------- | 
| Johnny Chen | bcec3af | 2011-01-27 01:26:19 +0000 | [diff] [blame] | 12459 |  | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 12460 | // push register(s) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12461 | { 0xfffffe00, 0x0000b400, ARMvAll,       eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulatePUSH, "push <registers>" }, | 
|  | 12462 | { 0xffff0000, 0xe92d0000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulatePUSH, "push.w <registers>" }, | 
|  | 12463 | { 0xffff0fff, 0xf84d0d04, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, &EmulateInstructionARM::EmulatePUSH, "push.w <register>" }, | 
| Johnny Chen | 788e055 | 2011-01-27 22:52:23 +0000 | [diff] [blame] | 12464 |  | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 12465 | // set r7 to point to a stack offset | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12466 | { 0xffffff00, 0x0000af00, ARMvAll,       eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateADDRdSPImm, "add r7, sp, #imm" }, | 
| Johnny Chen | e7cf420 | 2011-02-10 18:13:23 +0000 | [diff] [blame] | 12467 | // copy the stack pointer to r7 | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12468 | { 0xffffffff, 0x0000466f, ARMvAll,       eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateMOVRdSP, "mov r7, sp" }, | 
| Johnny Chen | e7cf420 | 2011-02-10 18:13:23 +0000 | [diff] [blame] | 12469 | // move from high register to low register (comes after "mov r7, sp" to resolve ambiguity) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12470 | { 0xffffffc0, 0x00004640, ARMvAll,       eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateMOVLowHigh, "mov r0-r7, r8-r15" }, | 
| Johnny Chen | 60c0d62 | 2011-01-25 23:49:39 +0000 | [diff] [blame] | 12471 |  | 
| Johnny Chen | 864a8e8 | 2011-02-18 00:07:39 +0000 | [diff] [blame] | 12472 | // PC-relative load into register (see also EmulateADDSPRm) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12473 | { 0xfffff800, 0x00004800, ARMvAll,       eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateLDRRtPCRelative, "ldr <Rt>, [PC, #imm]"}, | 
| Johnny Chen | 799dfd0 | 2011-01-26 23:14:33 +0000 | [diff] [blame] | 12474 |  | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 12475 | // adjust the stack pointer | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12476 | { 0xffffff87, 0x00004485, ARMvAll,       eEncodingT2, No_VFP, eSize16, &EmulateInstructionARM::EmulateADDSPRm, "add sp, <Rm>"}, | 
|  | 12477 | { 0xffffff80, 0x0000b080, ARMvAll,       eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateSUBSPImm, "sub sp, sp, #imm"}, | 
|  | 12478 | { 0xfbef8f00, 0xf1ad0d00, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBSPImm, "sub.w sp, sp, #<const>"}, | 
|  | 12479 | { 0xfbff8f00, 0xf2ad0d00, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBSPImm, "subw sp, sp, #imm12"}, | 
|  | 12480 | { 0xffef8000, 0xebad0000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBSPReg, "sub{s}<c> <Rd>, sp, <Rm>{,<shift>}" }, | 
| Johnny Chen | fdd179e | 2011-01-31 20:09:28 +0000 | [diff] [blame] | 12481 |  | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 12482 | // vector push consecutive extension register(s) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12483 | { 0xffbf0f00, 0xed2d0b00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateVPUSH, "vpush.64 <list>"}, | 
|  | 12484 | { 0xffbf0f00, 0xed2d0a00, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateVPUSH, "vpush.32 <list>"}, | 
| Johnny Chen | fdd179e | 2011-01-31 20:09:28 +0000 | [diff] [blame] | 12485 |  | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 12486 | //---------------------------------------------------------------------- | 
|  | 12487 | // Epilogue instructions | 
|  | 12488 | //---------------------------------------------------------------------- | 
| Johnny Chen | 347320d | 2011-01-24 23:40:59 +0000 | [diff] [blame] | 12489 |  | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12490 | { 0xfffff800, 0x0000a800, ARMV4T_ABOVE,  eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateADDSPImm, "add<c> <Rd>, sp, #imm"}, | 
|  | 12491 | { 0xffffff80, 0x0000b000, ARMvAll,       eEncodingT2, No_VFP, eSize16, &EmulateInstructionARM::EmulateADDSPImm, "add sp, #imm"}, | 
|  | 12492 | { 0xfffffe00, 0x0000bc00, ARMvAll,       eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulatePOP, "pop <registers>"}, | 
|  | 12493 | { 0xffff0000, 0xe8bd0000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulatePOP, "pop.w <registers>" }, | 
|  | 12494 | { 0xffff0fff, 0xf85d0d04, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, &EmulateInstructionARM::EmulatePOP, "pop.w <register>" }, | 
|  | 12495 | { 0xffbf0f00, 0xecbd0b00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateVPOP, "vpop.64 <list>"}, | 
|  | 12496 | { 0xffbf0f00, 0xecbd0a00, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateVPOP, "vpop.32 <list>"}, | 
| Johnny Chen | b77be41 | 2011-02-04 00:40:18 +0000 | [diff] [blame] | 12497 |  | 
|  | 12498 | //---------------------------------------------------------------------- | 
|  | 12499 | // Supervisor Call (previously Software Interrupt) | 
|  | 12500 | //---------------------------------------------------------------------- | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12501 | { 0xffffff00, 0x0000df00, ARMvAll,       eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateSVC, "svc #imm8"}, | 
| Johnny Chen | c315f86 | 2011-02-05 00:46:10 +0000 | [diff] [blame] | 12502 |  | 
|  | 12503 | //---------------------------------------------------------------------- | 
|  | 12504 | // If Then makes up to four following instructions conditional. | 
|  | 12505 | //---------------------------------------------------------------------- | 
| Greg Clayton | 04d397c | 2011-05-23 18:04:09 +0000 | [diff] [blame] | 12506 | // The next 5 opcode _must_ come before the if then instruction | 
|  | 12507 | { 0xffffffff, 0x0000bf00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateNop, "nop"}, | 
|  | 12508 | { 0xffffffff, 0x0000bf10, ARMV7_ABOVE,   eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateNop, "nop YIELD (yield hint)"}, | 
|  | 12509 | { 0xffffffff, 0x0000bf20, ARMV7_ABOVE,   eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateNop, "nop WFE (wait for event hint)"}, | 
|  | 12510 | { 0xffffffff, 0x0000bf30, ARMV7_ABOVE,   eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateNop, "nop WFI (wait for interrupt hint)"}, | 
|  | 12511 | { 0xffffffff, 0x0000bf40, ARMV7_ABOVE,   eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateNop, "nop SEV (send event hint)"}, | 
|  | 12512 | { 0xffffff00, 0x0000bf00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateIT, "it{<x>{<y>{<z>}}} <firstcond>"}, | 
| Johnny Chen | 3b620b3 | 2011-02-07 20:11:47 +0000 | [diff] [blame] | 12513 |  | 
|  | 12514 | //---------------------------------------------------------------------- | 
|  | 12515 | // Branch instructions | 
|  | 12516 | //---------------------------------------------------------------------- | 
|  | 12517 | // To resolve ambiguity, "b<c> #imm8" should come after "svc #imm8". | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12518 | { 0xfffff000, 0x0000d000, ARMvAll,       eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateB, "b<c> #imm8 (outside IT)"}, | 
|  | 12519 | { 0xfffff800, 0x0000e000, ARMvAll,       eEncodingT2, No_VFP, eSize16, &EmulateInstructionARM::EmulateB, "b<c> #imm11 (outside or last in IT)"}, | 
|  | 12520 | { 0xf800d000, 0xf0008000, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, &EmulateInstructionARM::EmulateB, "b<c>.w #imm8 (outside IT)"}, | 
|  | 12521 | { 0xf800d000, 0xf0009000, ARMV6T2_ABOVE, eEncodingT4, No_VFP, eSize32, &EmulateInstructionARM::EmulateB, "b<c>.w #imm8 (outside or last in IT)"}, | 
| Johnny Chen | 383d629 | 2011-02-11 21:23:32 +0000 | [diff] [blame] | 12522 | // J1 == J2 == 1 | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12523 | { 0xf800d000, 0xf000d000, ARMV4T_ABOVE,  eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateBLXImmediate, "bl <label>"}, | 
| Johnny Chen | 383d629 | 2011-02-11 21:23:32 +0000 | [diff] [blame] | 12524 | // J1 == J2 == 1 | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12525 | { 0xf800d001, 0xf000c000, ARMV5_ABOVE,   eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateBLXImmediate, "blx <label>"}, | 
|  | 12526 | { 0xffffff87, 0x00004780, ARMV5_ABOVE,   eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateBLXRm, "blx <Rm>"}, | 
| Johnny Chen | ab3b351 | 2011-02-12 00:10:51 +0000 | [diff] [blame] | 12527 | // for example, "bx lr" | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12528 | { 0xffffff87, 0x00004700, ARMvAll,       eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateBXRm, "bx <Rm>"}, | 
| Johnny Chen | 59e6ab7 | 2011-02-24 21:01:20 +0000 | [diff] [blame] | 12529 | // bxj | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12530 | { 0xfff0ffff, 0xf3c08f00, ARMV5J_ABOVE,  eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateBXJRm, "bxj <Rm>"}, | 
| Johnny Chen | 53ebab7 | 2011-02-08 23:21:57 +0000 | [diff] [blame] | 12531 | // compare and branch | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12532 | { 0xfffff500, 0x0000b100, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateCB, "cb{n}z <Rn>, <label>"}, | 
| Johnny Chen | 60299ec | 2011-02-17 19:34:27 +0000 | [diff] [blame] | 12533 | // table branch byte | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12534 | { 0xfff0fff0, 0xe8d0f000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateTB, "tbb<c> <Rn>, <Rm>"}, | 
| Johnny Chen | 60299ec | 2011-02-17 19:34:27 +0000 | [diff] [blame] | 12535 | // table branch halfword | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12536 | { 0xfff0fff0, 0xe8d0f010, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateTB, "tbh<c> <Rn>, <Rm>, lsl #1"}, | 
| Caroline Tice | b9f76c3 | 2011-02-08 22:24:38 +0000 | [diff] [blame] | 12537 |  | 
|  | 12538 | //---------------------------------------------------------------------- | 
| Johnny Chen | 26863dc | 2011-02-09 23:43:29 +0000 | [diff] [blame] | 12539 | // Data-processing instructions | 
|  | 12540 | //---------------------------------------------------------------------- | 
| Johnny Chen | 157b959 | 2011-02-18 21:13:05 +0000 | [diff] [blame] | 12541 | // adc (immediate) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12542 | { 0xfbe08000, 0xf1400000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateADCImm, "adc{s}<c> <Rd>, <Rn>, #<const>"}, | 
| Johnny Chen | 157b959 | 2011-02-18 21:13:05 +0000 | [diff] [blame] | 12543 | // adc (register) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12544 | { 0xffffffc0, 0x00004140, ARMvAll,       eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateADCReg, "adcs|adc<c> <Rdn>, <Rm>"}, | 
|  | 12545 | { 0xffe08000, 0xeb400000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateADCReg, "adc{s}<c>.w <Rd>, <Rn>, <Rm> {,<shift>}"}, | 
| Johnny Chen | 157b959 | 2011-02-18 21:13:05 +0000 | [diff] [blame] | 12546 | // add (register) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12547 | { 0xfffffe00, 0x00001800, ARMvAll,       eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateADDReg, "adds|add<c> <Rd>, <Rn>, <Rm>"}, | 
| Johnny Chen | 26863dc | 2011-02-09 23:43:29 +0000 | [diff] [blame] | 12548 | // Make sure "add sp, <Rm>" comes before this instruction, so there's no ambiguity decoding the two. | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12549 | { 0xffffff00, 0x00004400, ARMvAll,       eEncodingT2, No_VFP, eSize16, &EmulateInstructionARM::EmulateADDReg, "add<c> <Rdn>, <Rm>"}, | 
| Johnny Chen | a695f95 | 2011-02-23 21:24:25 +0000 | [diff] [blame] | 12550 | // adr | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12551 | { 0xfffff800, 0x0000a000, ARMvAll,       eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateADR, "add<c> <Rd>, PC, #<const>"}, | 
|  | 12552 | { 0xfbff8000, 0xf2af0000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateADR, "sub<c> <Rd>, PC, #<const>"}, | 
|  | 12553 | { 0xfbff8000, 0xf20f0000, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, &EmulateInstructionARM::EmulateADR, "add<c> <Rd>, PC, #<const>"}, | 
| Johnny Chen | e97c0d5 | 2011-02-18 19:32:20 +0000 | [diff] [blame] | 12554 | // and (immediate) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12555 | { 0xfbe08000, 0xf0000000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateANDImm, "and{s}<c> <Rd>, <Rn>, #<const>"}, | 
| Johnny Chen | e97c0d5 | 2011-02-18 19:32:20 +0000 | [diff] [blame] | 12556 | // and (register) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12557 | { 0xffffffc0, 0x00004000, ARMvAll,       eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateANDReg, "ands|and<c> <Rdn>, <Rm>"}, | 
|  | 12558 | { 0xffe08000, 0xea000000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateANDReg, "and{s}<c>.w <Rd>, <Rn>, <Rm> {,<shift>}"}, | 
| Johnny Chen | b9f02cf | 2011-02-24 01:15:17 +0000 | [diff] [blame] | 12559 | // bic (immediate) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12560 | { 0xfbe08000, 0xf0200000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateBICImm, "bic{s}<c> <Rd>, <Rn>, #<const>"}, | 
| Johnny Chen | b9f02cf | 2011-02-24 01:15:17 +0000 | [diff] [blame] | 12561 | // bic (register) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12562 | { 0xffffffc0, 0x00004380, ARMvAll,       eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateBICReg, "bics|bic<c> <Rdn>, <Rm>"}, | 
|  | 12563 | { 0xffe08000, 0xea200000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateBICReg, "bic{s}<c>.w <Rd>, <Rn>, <Rm> {,<shift>}"}, | 
| Johnny Chen | 2115b41 | 2011-02-21 23:42:44 +0000 | [diff] [blame] | 12564 | // eor (immediate) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12565 | { 0xfbe08000, 0xf0800000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateEORImm, "eor{s}<c> <Rd>, <Rn>, #<const>"}, | 
| Johnny Chen | 2115b41 | 2011-02-21 23:42:44 +0000 | [diff] [blame] | 12566 | // eor (register) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12567 | { 0xffffffc0, 0x00004040, ARMvAll,       eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateEORReg, "eors|eor<c> <Rdn>, <Rm>"}, | 
|  | 12568 | { 0xffe08000, 0xea800000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateEORReg, "eor{s}<c>.w <Rd>, <Rn>, <Rm> {,<shift>}"}, | 
| Johnny Chen | 7c5234d | 2011-02-18 23:41:11 +0000 | [diff] [blame] | 12569 | // orr (immediate) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12570 | { 0xfbe08000, 0xf0400000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateORRImm, "orr{s}<c> <Rd>, <Rn>, #<const>"}, | 
| Johnny Chen | 7c5234d | 2011-02-18 23:41:11 +0000 | [diff] [blame] | 12571 | // orr (register) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12572 | { 0xffffffc0, 0x00004300, ARMvAll,       eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateORRReg, "orrs|orr<c> <Rdn>, <Rm>"}, | 
|  | 12573 | { 0xffe08000, 0xea400000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateORRReg, "orr{s}<c>.w <Rd>, <Rn>, <Rm> {,<shift>}"}, | 
| Johnny Chen | ed32e7c | 2011-02-22 23:42:58 +0000 | [diff] [blame] | 12574 | // rsb (immediate) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12575 | { 0xffffffc0, 0x00004240, ARMvAll,       eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateRSBImm, "rsbs|rsb<c> <Rd>, <Rn>, #0"}, | 
|  | 12576 | { 0xfbe08000, 0xf1c00000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateRSBImm, "rsb{s}<c>.w <Rd>, <Rn>, #<const>"}, | 
| Johnny Chen | ed32e7c | 2011-02-22 23:42:58 +0000 | [diff] [blame] | 12577 | // rsb (register) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12578 | { 0xffe08000, 0xea400000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateRSBReg, "rsb{s}<c>.w <Rd>, <Rn>, <Rm> {,<shift>}"}, | 
| Johnny Chen | 9b38177 | 2011-02-23 01:01:21 +0000 | [diff] [blame] | 12579 | // sbc (immediate) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12580 | { 0xfbe08000, 0xf1600000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSBCImm, "sbc{s}<c> <Rd>, <Rn>, #<const>"}, | 
| Johnny Chen | 9b38177 | 2011-02-23 01:01:21 +0000 | [diff] [blame] | 12581 | // sbc (register) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12582 | { 0xffffffc0, 0x00004180, ARMvAll,       eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateSBCReg, "sbcs|sbc<c> <Rdn>, <Rm>"}, | 
|  | 12583 | { 0xffe08000, 0xeb600000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateSBCReg, "sbc{s}<c>.w <Rd>, <Rn>, <Rm> {,<shift>}"}, | 
| Caroline Tice | dcc11b3 | 2011-03-02 23:57:02 +0000 | [diff] [blame] | 12584 | // add (immediate, Thumb) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12585 | { 0xfffffe00, 0x00001c00, ARMV4T_ABOVE,  eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateADDImmThumb, "adds|add<c> <Rd>,<Rn>,#<imm3>" }, | 
|  | 12586 | { 0xfffff800, 0x00003000, ARMV4T_ABOVE,  eEncodingT2, No_VFP, eSize16, &EmulateInstructionARM::EmulateADDImmThumb, "adds|add<c> <Rdn>,#<imm8>" }, | 
|  | 12587 | { 0xfbe08000, 0xf1000000, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, &EmulateInstructionARM::EmulateADDImmThumb, "add{s}<c>.w <Rd>,<Rn>,#<const>" }, | 
|  | 12588 | { 0xfbf08000, 0xf2000000, ARMV6T2_ABOVE, eEncodingT4, No_VFP, eSize32, &EmulateInstructionARM::EmulateADDImmThumb, "addw<c> <Rd>,<Rn>,#<imm12>" }, | 
| Johnny Chen | 15a7a6b | 2011-02-23 23:47:56 +0000 | [diff] [blame] | 12589 | // sub (immediate, Thumb) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12590 | { 0xfffffe00, 0x00001e00, ARMvAll,       eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateSUBImmThumb, "subs|sub<c> <Rd>, <Rn> #imm3"}, | 
|  | 12591 | { 0xfffff800, 0x00003800, ARMvAll,       eEncodingT2, No_VFP, eSize16, &EmulateInstructionARM::EmulateSUBImmThumb, "subs|sub<c> <Rdn>, #imm8"}, | 
|  | 12592 | { 0xfbe08000, 0xf1a00000, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBImmThumb, "sub{s}<c>.w <Rd>, <Rn>, #<const>"}, | 
|  | 12593 | { 0xfbf08000, 0xf2a00000, ARMV6T2_ABOVE, eEncodingT4, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBImmThumb, "subw<c> <Rd>, <Rn>, #imm12"}, | 
| Johnny Chen | c9e747f | 2011-02-23 01:55:07 +0000 | [diff] [blame] | 12594 | // sub (sp minus immediate) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12595 | { 0xfbef8000, 0xf1ad0000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBSPImm, "sub{s}.w <Rd>, sp, #<const>"}, | 
|  | 12596 | { 0xfbff8000, 0xf2ad0000, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBSPImm, "subw<c> <Rd>, sp, #imm12"}, | 
| Caroline Tice | 4cccd53 | 2011-03-29 23:44:20 +0000 | [diff] [blame] | 12597 | // sub (register) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12598 | { 0xfffffe00, 0x00001a00, ARMV4T_ABOVE,  eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateSUBReg, "subs|sub<c> <Rd>, <Rn>, <Rm>"}, | 
|  | 12599 | { 0xffe08000, 0xeba00000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBReg, "sub{s}<c>.w <Rd>, <Rn>, <Rm>{,<shift>}"}, | 
| Johnny Chen | 2115b41 | 2011-02-21 23:42:44 +0000 | [diff] [blame] | 12600 | // teq (immediate) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12601 | { 0xfbf08f00, 0xf0900f00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateTEQImm, "teq<c> <Rn>, #<const>"}, | 
| Johnny Chen | 2115b41 | 2011-02-21 23:42:44 +0000 | [diff] [blame] | 12602 | // teq (register) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12603 | { 0xfff08f00, 0xea900f00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateTEQReg, "teq<c> <Rn>, <Rm> {,<shift>}"}, | 
| Johnny Chen | de3cce3 | 2011-02-21 21:24:49 +0000 | [diff] [blame] | 12604 | // tst (immediate) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12605 | { 0xfbf08f00, 0xf0100f00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateTSTImm, "tst<c> <Rn>, #<const>"}, | 
| Johnny Chen | de3cce3 | 2011-02-21 21:24:49 +0000 | [diff] [blame] | 12606 | // tst (register) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12607 | { 0xffffffc0, 0x00004200, ARMvAll,       eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateTSTReg, "tst<c> <Rdn>, <Rm>"}, | 
|  | 12608 | { 0xfff08f00, 0xea100f00, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateTSTReg, "tst<c>.w <Rn>, <Rm> {,<shift>}"}, | 
| Johnny Chen | de3cce3 | 2011-02-21 21:24:49 +0000 | [diff] [blame] | 12609 |  | 
| Johnny Chen | 7c5234d | 2011-02-18 23:41:11 +0000 | [diff] [blame] | 12610 |  | 
| Johnny Chen | 338bf54 | 2011-02-10 19:29:03 +0000 | [diff] [blame] | 12611 | // move from high register to high register | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12612 | { 0xffffff00, 0x00004600, ARMvAll,       eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateMOVRdRm, "mov<c> <Rd>, <Rm>"}, | 
| Johnny Chen | 338bf54 | 2011-02-10 19:29:03 +0000 | [diff] [blame] | 12613 | // move from low register to low register | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12614 | { 0xffffffc0, 0x00000000, ARMvAll,       eEncodingT2, No_VFP, eSize16, &EmulateInstructionARM::EmulateMOVRdRm, "movs <Rd>, <Rm>"}, | 
| Johnny Chen | 7c5234d | 2011-02-18 23:41:11 +0000 | [diff] [blame] | 12615 | // mov{s}<c>.w <Rd>, <Rm> | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12616 | { 0xffeff0f0, 0xea4f0000, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, &EmulateInstructionARM::EmulateMOVRdRm, "mov{s}<c>.w <Rd>, <Rm>"}, | 
| Johnny Chen | 357c30f | 2011-02-14 22:04:25 +0000 | [diff] [blame] | 12617 | // move immediate | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12618 | { 0xfffff800, 0x00002000, ARMvAll,       eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateMOVRdImm, "movs|mov<c> <Rd>, #imm8"}, | 
|  | 12619 | { 0xfbef8000, 0xf04f0000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateMOVRdImm, "mov{s}<c>.w <Rd>, #<const>"}, | 
|  | 12620 | { 0xfbf08000, 0xf2400000, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, &EmulateInstructionARM::EmulateMOVRdImm, "movw<c> <Rd>,#<imm16>"}, | 
| Johnny Chen | d642a6a | 2011-02-22 01:01:03 +0000 | [diff] [blame] | 12621 | // mvn (immediate) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12622 | { 0xfbef8000, 0xf06f0000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateMVNImm, "mvn{s} <Rd>, #<const>"}, | 
| Johnny Chen | d642a6a | 2011-02-22 01:01:03 +0000 | [diff] [blame] | 12623 | // mvn (register) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12624 | { 0xffffffc0, 0x000043c0, ARMvAll,       eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateMVNReg, "mvns|mvn<c> <Rd>, <Rm>"}, | 
|  | 12625 | { 0xffef8000, 0xea6f0000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateMVNReg, "mvn{s}<c>.w <Rd>, <Rm> {,<shift>}"}, | 
| Johnny Chen | 34075cb | 2011-02-22 01:56:31 +0000 | [diff] [blame] | 12626 | // cmn (immediate) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12627 | { 0xfbf08f00, 0xf1100f00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateCMNImm, "cmn<c> <Rn>, #<const>"}, | 
| Johnny Chen | 34075cb | 2011-02-22 01:56:31 +0000 | [diff] [blame] | 12628 | // cmn (register) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12629 | { 0xffffffc0, 0x000042c0, ARMvAll,       eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateCMNReg, "cmn<c> <Rn>, <Rm>"}, | 
|  | 12630 | { 0xfff08f00, 0xeb100f00, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateCMNReg, "cmn<c> <Rn>, <Rm> {,<shift>}"}, | 
| Johnny Chen | 34075cb | 2011-02-22 01:56:31 +0000 | [diff] [blame] | 12631 | // cmp (immediate) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12632 | { 0xfffff800, 0x00002800, ARMvAll,       eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateCMPImm, "cmp<c> <Rn>, #imm8"}, | 
|  | 12633 | { 0xfbf08f00, 0xf1b00f00, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateCMPImm, "cmp<c>.w <Rn>, #<const>"}, | 
| Johnny Chen | 34075cb | 2011-02-22 01:56:31 +0000 | [diff] [blame] | 12634 | // cmp (register) (Rn and Rm both from r0-r7) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12635 | { 0xffffffc0, 0x00004280, ARMvAll,       eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateCMPReg, "cmp<c> <Rn>, <Rm>"}, | 
| Johnny Chen | 34075cb | 2011-02-22 01:56:31 +0000 | [diff] [blame] | 12636 | // cmp (register) (Rn and Rm not both from r0-r7) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12637 | { 0xffffff00, 0x00004500, ARMvAll,       eEncodingT2, No_VFP, eSize16, &EmulateInstructionARM::EmulateCMPReg, "cmp<c> <Rn>, <Rm>"}, | 
| Johnny Chen | 82f16aa | 2011-02-15 20:10:55 +0000 | [diff] [blame] | 12638 | // asr (immediate) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12639 | { 0xfffff800, 0x00001000, ARMvAll,       eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateASRImm, "asrs|asr<c> <Rd>, <Rm>, #imm"}, | 
|  | 12640 | { 0xffef8030, 0xea4f0020, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateASRImm, "asr{s}<c>.w <Rd>, <Rm>, #imm"}, | 
| Johnny Chen | e7f8953 | 2011-02-15 23:22:46 +0000 | [diff] [blame] | 12641 | // asr (register) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12642 | { 0xffffffc0, 0x00004100, ARMvAll,       eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateASRReg, "asrs|asr<c> <Rdn>, <Rm>"}, | 
|  | 12643 | { 0xffe0f0f0, 0xfa40f000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateASRReg, "asr{s}<c>.w <Rd>, <Rn>, <Rm>"}, | 
| Johnny Chen | 2ee35bc | 2011-02-16 19:27:43 +0000 | [diff] [blame] | 12644 | // lsl (immediate) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12645 | { 0xfffff800, 0x00000000, ARMvAll,       eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateLSLImm, "lsls|lsl<c> <Rd>, <Rm>, #imm"}, | 
|  | 12646 | { 0xffef8030, 0xea4f0000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateLSLImm, "lsl{s}<c>.w <Rd>, <Rm>, #imm"}, | 
| Johnny Chen | 2ee35bc | 2011-02-16 19:27:43 +0000 | [diff] [blame] | 12647 | // lsl (register) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12648 | { 0xffffffc0, 0x00004080, ARMvAll,       eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateLSLReg, "lsls|lsl<c> <Rdn>, <Rm>"}, | 
|  | 12649 | { 0xffe0f0f0, 0xfa00f000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateLSLReg, "lsl{s}<c>.w <Rd>, <Rn>, <Rm>"}, | 
| Johnny Chen | 2ee35bc | 2011-02-16 19:27:43 +0000 | [diff] [blame] | 12650 | // lsr (immediate) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12651 | { 0xfffff800, 0x00000800, ARMvAll,       eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateLSRImm, "lsrs|lsr<c> <Rd>, <Rm>, #imm"}, | 
|  | 12652 | { 0xffef8030, 0xea4f0010, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateLSRImm, "lsr{s}<c>.w <Rd>, <Rm>, #imm"}, | 
| Johnny Chen | 2ee35bc | 2011-02-16 19:27:43 +0000 | [diff] [blame] | 12653 | // lsr (register) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12654 | { 0xffffffc0, 0x000040c0, ARMvAll,       eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateLSRReg, "lsrs|lsr<c> <Rdn>, <Rm>"}, | 
|  | 12655 | { 0xffe0f0f0, 0xfa20f000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateLSRReg, "lsr{s}<c>.w <Rd>, <Rn>, <Rm>"}, | 
| Johnny Chen | eeab485 | 2011-02-16 22:14:44 +0000 | [diff] [blame] | 12656 | // rrx is a special case encoding of ror (immediate) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12657 | { 0xffeff0f0, 0xea4f0030, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateRRX, "rrx{s}<c>.w <Rd>, <Rm>"}, | 
| Johnny Chen | eeab485 | 2011-02-16 22:14:44 +0000 | [diff] [blame] | 12658 | // ror (immediate) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12659 | { 0xffef8030, 0xea4f0030, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateRORImm, "ror{s}<c>.w <Rd>, <Rm>, #imm"}, | 
| Johnny Chen | eeab485 | 2011-02-16 22:14:44 +0000 | [diff] [blame] | 12660 | // ror (register) | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12661 | { 0xffffffc0, 0x000041c0, ARMvAll,       eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateRORReg, "rors|ror<c> <Rdn>, <Rm>"}, | 
|  | 12662 | { 0xffe0f0f0, 0xfa60f000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateRORReg, "ror{s}<c>.w <Rd>, <Rn>, <Rm>"}, | 
| Caroline Tice | 5c1e2ed | 2011-03-02 22:43:54 +0000 | [diff] [blame] | 12663 | // mul | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12664 | { 0xffffffc0, 0x00004340, ARMV4T_ABOVE,  eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateMUL, "muls <Rdm>,<Rn>,<Rdm>" }, | 
| Caroline Tice | 5c1e2ed | 2011-03-02 22:43:54 +0000 | [diff] [blame] | 12665 | // mul | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12666 | { 0xfff0f0f0, 0xfb00f000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateMUL, "mul<c> <Rd>,<Rn>,<Rm>" }, | 
| Caroline Tice | 6b8d3b5 | 2011-04-19 23:30:03 +0000 | [diff] [blame] | 12667 |  | 
|  | 12668 | // subs pc, lr and related instructions | 
| Caroline Tice | 1f954f5 | 2011-04-11 15:51:10 +0000 | [diff] [blame] | 12669 | { 0xffffff00, 0xf3de8f00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBSPcLrEtc, "SUBS<c> PC, LR, #<imm8>" }, | 
| Caroline Tice | 080bf61 | 2011-04-05 18:46:00 +0000 | [diff] [blame] | 12670 |  | 
|  | 12671 | //---------------------------------------------------------------------- | 
|  | 12672 | // RFE instructions  *** IMPORTANT *** THESE MUST BE LISTED **BEFORE** THE LDM.. Instructions in this table; | 
|  | 12673 | // otherwise the wrong instructions will be selected. | 
|  | 12674 | //---------------------------------------------------------------------- | 
| Caroline Tice | 6bf6516 | 2011-03-03 17:42:58 +0000 | [diff] [blame] | 12675 |  | 
| Caroline Tice | 080bf61 | 2011-04-05 18:46:00 +0000 | [diff] [blame] | 12676 | { 0xffd0ffff, 0xe810c000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateRFE, "rfedb<c> <Rn>{!}" }, | 
|  | 12677 | { 0xffd0ffff, 0xe990c000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateRFE, "rfe{ia}<c> <Rn>{!}" }, | 
|  | 12678 |  | 
| Johnny Chen | 26863dc | 2011-02-09 23:43:29 +0000 | [diff] [blame] | 12679 | //---------------------------------------------------------------------- | 
| Caroline Tice | b9f76c3 | 2011-02-08 22:24:38 +0000 | [diff] [blame] | 12680 | // Load instructions | 
|  | 12681 | //---------------------------------------------------------------------- | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12682 | { 0xfffff800, 0x0000c800, ARMV4T_ABOVE,  eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateLDM, "ldm<c> <Rn>{!} <registers>" }, | 
|  | 12683 | { 0xffd02000, 0xe8900000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDM, "ldm<c>.w <Rn>{!} <registers>" }, | 
|  | 12684 | { 0xffd00000, 0xe9100000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDMDB, "ldmdb<c> <Rn>{!} <registers>" }, | 
|  | 12685 | { 0xfffff800, 0x00006800, ARMV4T_ABOVE,  eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateLDRRtRnImm, "ldr<c> <Rt>, [<Rn>{,#imm}]"}, | 
|  | 12686 | { 0xfffff800, 0x00009800, ARMV4T_ABOVE,  eEncodingT2, No_VFP, eSize16, &EmulateInstructionARM::EmulateLDRRtRnImm, "ldr<c> <Rt>, [SP{,#imm}]"}, | 
|  | 12687 | { 0xfff00000, 0xf8d00000, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRRtRnImm, "ldr<c>.w <Rt>, [<Rn>{,#imm12}]"}, | 
|  | 12688 | { 0xfff00800, 0xf8500800, ARMV6T2_ABOVE, eEncodingT4, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRRtRnImm, "ldr<c> <Rt>, [<Rn>{,#+/-<imm8>}]{!}"}, | 
| Caroline Tice | baf1f64 | 2011-03-24 19:23:45 +0000 | [diff] [blame] | 12689 | // Thumb2 PC-relative load into register | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12690 | { 0xff7f0000, 0xf85f0000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRRtPCRelative, "ldr<c>.w <Rt>, [PC, +/-#imm}]"}, | 
|  | 12691 | { 0xfffffe00, 0x00005800, ARMV4T_ABOVE,  eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateLDRRegister, "ldr<c> <Rt>, [<Rn>, <Rm>]" }, | 
|  | 12692 | { 0xfff00fc0, 0xf8500000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRRegister, "ldr<c>.w <Rt>, [<Rn>,<Rm>{,LSL #<imm2>}]" }, | 
|  | 12693 | { 0xfffff800, 0x00007800, ARMV4T_ABOVE,  eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateLDRBImmediate, "ldrb<c> <Rt>,[<Rn>{,#<imm5>}]" }, | 
|  | 12694 | { 0xfff00000, 0xf8900000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRBImmediate, "ldrb<c>.w <Rt>,[<Rn>{,#<imm12>}]" }, | 
| Caroline Tice | 0fe5a53 | 2011-04-08 23:33:06 +0000 | [diff] [blame] | 12695 | { 0xfff00800, 0xf8100800, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRBImmediate, "ldrb<c> <Rt>,[<Rn>, #+/-<imm8>]{!}" }, | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12696 | { 0xff7f0000, 0xf81f0000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRBLiteral, "ldrb<c> <Rt>,[...]" }, | 
|  | 12697 | { 0xfffffe00, 0x00005c00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateLDRBRegister, "ldrb<c> <Rt>,[<Rn>,<Rm>]" }, | 
|  | 12698 | { 0xfff00fc0, 0xf8100000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRBRegister, "ldrb<c>.w <Rt>,[<Rn>,<Rm>{,LSL #imm2>}]" }, | 
|  | 12699 | { 0xfffff800, 0x00008800, ARMV4T_ABOVE,  eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateLDRHImmediate, "ldrh<c> <Rt>, [<Rn>{,#<imm>}]"  }, | 
|  | 12700 | { 0xfff00000, 0xf8b00000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRHImmediate, "ldrh<c>.w <Rt>,[<Rn>{,#<imm12>}]" }, | 
|  | 12701 | { 0xfff00800, 0xf8300800, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRHImmediate, "ldrh<c> <Rt>,[<Rn>,#+/-<imm8>]{!}"  }, | 
|  | 12702 | { 0xff7f0000, 0xf83f0000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRHLiteral, "ldrh<c> <Rt>, <label>" }, | 
|  | 12703 | { 0xfffffe00, 0x00005a00, ARMV4T_ABOVE,  eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateLDRHRegister, "ldrh<c> <Rt>, [<Rn>,<Rm>]" }, | 
|  | 12704 | { 0xfff00fc0, 0xf8300000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRHRegister, "ldrh<c>.w <Rt>,[<Rn>,<Rm>{,LSL #<imm2>}]" }, | 
|  | 12705 | { 0xfff00000, 0xf9900000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRSBImmediate, "ldrsb<c> <Rt>,[<Rn>,#<imm12>]" }, | 
|  | 12706 | { 0xfff00800, 0xf9100800, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRSBImmediate, "ldrsb<c> <Rt>,[<Rn>,#+/-<imm8>]" }, | 
|  | 12707 | { 0xff7f0000, 0xf91f0000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRSBLiteral, "ldrsb<c> <Rt>, <label>" }, | 
|  | 12708 | { 0xfffffe00, 0x00005600, ARMV4T_ABOVE,  eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateLDRSBRegister, "ldrsb<c> <Rt>,[<Rn>,<Rm>]" }, | 
|  | 12709 | { 0xfff00fc0, 0xf9100000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRSBRegister, "ldrsb<c>.w <Rt>,[<Rn>,<Rm>{,LSL #imm2>}]"  }, | 
|  | 12710 | { 0xfff00000, 0xf9b00000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRSHImmediate, "ldrsh<c> <Rt>,[<Rn>,#<imm12>]" }, | 
|  | 12711 | { 0xfff00800, 0xf9300800, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRSHImmediate, "ldrsh<c> <Rt>,[<Rn>,#+/-<imm8>]" }, | 
|  | 12712 | { 0xff7f0000, 0xf93f0000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRSHLiteral, "ldrsh<c> <Rt>,<label>" }, | 
|  | 12713 | { 0xfffffe00, 0x00005e00, ARMV4T_ABOVE,  eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateLDRSHRegister, "ldrsh<c> <Rt>,[<Rn>,<Rm>]" }, | 
|  | 12714 | { 0xfff00fc0, 0xf9300000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRSHRegister, "ldrsh<c>.w <Rt>,[<Rn>,<Rm>{,LSL #<imm2>}]" }, | 
| Caroline Tice | 0fe5a53 | 2011-04-08 23:33:06 +0000 | [diff] [blame] | 12715 | { 0xfe500000, 0xe8500000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRDImmediate, "ldrd<c> <Rt>, <Rt2>, [<Rn>,#+/-<imm>]!"}, | 
| Caroline Tice | 9121b35 | 2011-03-31 16:41:19 +0000 | [diff] [blame] | 12716 | { 0xfe100f00, 0xec100b00, ARMvAll,       eEncodingT1, VFPv2_ABOVE,  eSize32, &EmulateInstructionARM::EmulateVLDM, "vldm{mode}<c> <Rn>{!}, <list>"}, | 
|  | 12717 | { 0xfe100f00, 0xec100a00, ARMvAll,       eEncodingT2, VFPv2v3,      eSize32, &EmulateInstructionARM::EmulateVLDM, "vldm{mode}<c> <Rn>{!}, <list>" }, | 
|  | 12718 | { 0xffe00f00, 0xed100b00, ARMvAll,       eEncodingT1, VFPv2_ABOVE,  eSize32, &EmulateInstructionARM::EmulateVLDR, "vldr<c> <Dd>, [<Rn>{,#+/-<imm>}]"}, | 
|  | 12719 | { 0xff300f00, 0xed100a00, ARMvAll,       eEncodingT2, VFPv2v3,      eSize32, &EmulateInstructionARM::EmulateVLDR, "vldr<c> <Sd>, {<Rn>{,#+/-<imm>}]"}, | 
| Caroline Tice | b6281b1 | 2011-03-31 17:58:23 +0000 | [diff] [blame] | 12720 | { 0xffb00000, 0xf9200000, ARMvAll,       eEncodingT1, AdvancedSIMD, eSize32, &EmulateInstructionARM::EmulateVLD1Multiple, "vld1<c>.<size> <list>, [<Rn>{@<align>}],<Rm>"}, | 
|  | 12721 | { 0xffb00300, 0xf9a00000, ARMvAll,       eEncodingT1, AdvancedSIMD, eSize32, &EmulateInstructionARM::EmulateVLD1Single, "vld1<c>.<size> <list>, [<Rn>{@<align>}],<Rm>"}, | 
| Caroline Tice | 93767b8 | 2011-03-31 21:15:29 +0000 | [diff] [blame] | 12722 | { 0xffb00f00, 0xf9a00c00, ARMvAll,       eEncodingT1, AdvancedSIMD, eSize32, &EmulateInstructionARM::EmulateVLD1SingleAll, "vld1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>"}, | 
| Caroline Tice | fa17220 | 2011-02-11 22:49:54 +0000 | [diff] [blame] | 12723 |  | 
|  | 12724 | //---------------------------------------------------------------------- | 
|  | 12725 | // Store instructions | 
|  | 12726 | //---------------------------------------------------------------------- | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12727 | { 0xfffff800, 0x0000c000, ARMV4T_ABOVE,  eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateSTM, "stm<c> <Rn>{!} <registers>" }, | 
|  | 12728 | { 0xffd00000, 0xe8800000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTM, "stm<c>.w <Rn>{!} <registers>" }, | 
|  | 12729 | { 0xffd00000, 0xe9000000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTMDB, "stmdb<c> <Rn>{!} <registers>" }, | 
|  | 12730 | { 0xfffff800, 0x00006000, ARMV4T_ABOVE,  eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateSTRThumb, "str<c> <Rt>, [<Rn>{,#<imm>}]" }, | 
|  | 12731 | { 0xfffff800, 0x00009000, ARMV4T_ABOVE,  eEncodingT2, No_VFP, eSize16, &EmulateInstructionARM::EmulateSTRThumb, "str<c> <Rt>, [SP,#<imm>]" }, | 
|  | 12732 | { 0xfff00000, 0xf8c00000, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTRThumb, "str<c>.w <Rt>, [<Rn>,#<imm12>]" }, | 
|  | 12733 | { 0xfff00800, 0xf8400800, ARMV6T2_ABOVE, eEncodingT4, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTRThumb, "str<c> <Rt>, [<Rn>,#+/-<imm8>]" }, | 
|  | 12734 | { 0xfffffe00, 0x00005000, ARMV4T_ABOVE,  eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateSTRRegister, "str<c> <Rt> ,{<Rn>, <Rm>]" }, | 
|  | 12735 | { 0xfff00fc0, 0xf8400000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTRRegister, "str<c>.w <Rt>, [<Rn>, <Rm> {lsl #imm2>}]" }, | 
|  | 12736 | { 0xfffff800, 0x00007000, ARMV4T_ABOVE,  eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateSTRBThumb, "strb<c> <Rt>, [<Rn>, #<imm5>]" }, | 
|  | 12737 | { 0xfff00000, 0xf8800000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTRBThumb, "strb<c>.w <Rt>, [<Rn>, #<imm12>]" }, | 
|  | 12738 | { 0xfff00800, 0xf8000800, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTRBThumb, "strb<c> <Rt> ,[<Rn>, #+/-<imm8>]{!}" }, | 
|  | 12739 | { 0xfffffe00, 0x00005200, ARMV4T_ABOVE,  eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateSTRHRegister, "strh<c> <Rt>,[<Rn>,<Rm>]" }, | 
|  | 12740 | { 0xfff00fc0, 0xf8200000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTRHRegister, "strh<c>.w <Rt>,[<Rn>,<Rm>{,LSL #<imm2>}]" }, | 
|  | 12741 | { 0xfff00000, 0xe8400000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTREX, "strex<c> <Rd>, <Rt>, [<Rn{,#<imm>}]" }, | 
|  | 12742 | { 0xfe500000, 0xe8400000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTRDImm, "strd<c> <Rt>, <Rt2>, [<Rn>, #+/-<imm>]!"}, | 
| Caroline Tice | 1e542e3 | 2011-03-31 18:44:04 +0000 | [diff] [blame] | 12743 | { 0xfe100f00, 0xec000b00, ARMvAll,       eEncodingT1, VFPv2_ABOVE,  eSize32, &EmulateInstructionARM::EmulateVSTM, "vstm{mode}<c> <Rn>{!}, <list>"}, | 
|  | 12744 | { 0xfea00f00, 0xec000a00, ARMvAll,       eEncodingT2, VFPv2v3,      eSize32, &EmulateInstructionARM::EmulateVSTM, "vstm{mode}<c> <Rn>{!}, <list>"}, | 
|  | 12745 | { 0xff300f00, 0xed000b00, ARMvAll,       eEncodingT1, VFPv2_ABOVE,  eSize32, &EmulateInstructionARM::EmulateVSTR, "vstr<c> <Dd>, [<Rn>{,#+/-<imm>}]"}, | 
|  | 12746 | { 0xff300f00, 0xed000a00, ARMvAll,       eEncodingT2, VFPv2v3,      eSize32, &EmulateInstructionARM::EmulateVSTR, "vstr<c> <Sd>, [<Rn>{,#+/-<imm>}]"}, | 
|  | 12747 | { 0xffb00000, 0xfa000000, ARMvAll,       eEncodingT1, AdvancedSIMD, eSize32, &EmulateInstructionARM::EmulateVST1Multiple, "vst1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>"}, | 
| Caroline Tice | 7b88094 | 2011-03-31 19:17:12 +0000 | [diff] [blame] | 12748 | { 0xffb00300, 0xf9800000, ARMvAll,       eEncodingT1, AdvancedSIMD, eSize32, &EmulateInstructionARM::EmulateVST1Single, "vst1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>"}, | 
| Caroline Tice | 6bf6516 | 2011-03-03 17:42:58 +0000 | [diff] [blame] | 12749 |  | 
|  | 12750 | //---------------------------------------------------------------------- | 
|  | 12751 | // Other instructions | 
|  | 12752 | //---------------------------------------------------------------------- | 
| Caroline Tice | 4f60558 | 2011-03-31 00:02:51 +0000 | [diff] [blame] | 12753 | { 0xffffffc0, 0x0000b240, ARMV6_ABOVE,   eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateSXTB, "sxtb<c> <Rd>,<Rm>" }, | 
|  | 12754 | { 0xfffff080, 0xfa4ff080, ARMV6_ABOVE,   eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateSXTB, "sxtb<c>.w <Rd>,<Rm>{,<rotation>}" }, | 
|  | 12755 | { 0xffffffc0, 0x0000b200, ARMV6_ABOVE,   eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateSXTH, "sxth<c> <Rd>,<Rm>" }, | 
|  | 12756 | { 0xfffff080, 0xfa0ff080, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateSXTH, "sxth<c>.w <Rd>,<Rm>{,<rotation>}" }, | 
|  | 12757 | { 0xffffffc0, 0x0000b2c0, ARMV6_ABOVE,   eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateUXTB, "uxtb<c> <Rd>,<Rm>" }, | 
|  | 12758 | { 0xfffff080, 0xfa5ff080, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateUXTB, "uxtb<c>.w <Rd>,<Rm>{,<rotation>}" }, | 
|  | 12759 | { 0xffffffc0, 0x0000b280, ARMV6_ABOVE,   eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateUXTH, "uxth<c> <Rd>,<Rm>" }, | 
|  | 12760 | { 0xfffff080, 0xfa1ff080, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateUXTH, "uxth<c>.w <Rd>,<Rm>{,<rotation>}" }, | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 12761 | }; | 
|  | 12762 |  | 
|  | 12763 | const size_t k_num_thumb_opcodes = sizeof(g_thumb_opcodes)/sizeof(ARMOpcode); | 
|  | 12764 | for (size_t i=0; i<k_num_thumb_opcodes; ++i) | 
|  | 12765 | { | 
| Greg Clayton | 888a733 | 2011-04-26 04:39:08 +0000 | [diff] [blame] | 12766 | if ((g_thumb_opcodes[i].mask & opcode) == g_thumb_opcodes[i].value && | 
|  | 12767 | (g_thumb_opcodes[i].variants & arm_isa) != 0) | 
| Greg Clayton | 2b8e8b0 | 2011-02-01 00:49:32 +0000 | [diff] [blame] | 12768 | return &g_thumb_opcodes[i]; | 
|  | 12769 | } | 
|  | 12770 | return NULL; | 
|  | 12771 | } | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 12772 |  | 
| Greg Clayton | 31e2a38 | 2011-01-30 20:03:56 +0000 | [diff] [blame] | 12773 | bool | 
| Greg Clayton | 395fc33 | 2011-02-15 21:59:32 +0000 | [diff] [blame] | 12774 | EmulateInstructionARM::SetArchitecture (const ArchSpec &arch) | 
| Greg Clayton | 31e2a38 | 2011-01-30 20:03:56 +0000 | [diff] [blame] | 12775 | { | 
| Caroline Tice | 080bf61 | 2011-04-05 18:46:00 +0000 | [diff] [blame] | 12776 | m_arch = arch; | 
| Greg Clayton | 31e2a38 | 2011-01-30 20:03:56 +0000 | [diff] [blame] | 12777 | m_arm_isa = 0; | 
| Greg Clayton | 940b103 | 2011-02-23 00:35:02 +0000 | [diff] [blame] | 12778 | const char *arch_cstr = arch.GetArchitectureName (); | 
| Greg Clayton | 395fc33 | 2011-02-15 21:59:32 +0000 | [diff] [blame] | 12779 | if (arch_cstr) | 
| Greg Clayton | 31e2a38 | 2011-01-30 20:03:56 +0000 | [diff] [blame] | 12780 | { | 
| Greg Clayton | 395fc33 | 2011-02-15 21:59:32 +0000 | [diff] [blame] | 12781 | if      (0 == ::strcasecmp(arch_cstr, "armv4t"))    m_arm_isa = ARMv4T; | 
|  | 12782 | else if (0 == ::strcasecmp(arch_cstr, "armv4"))     m_arm_isa = ARMv4; | 
|  | 12783 | else if (0 == ::strcasecmp(arch_cstr, "armv5tej"))  m_arm_isa = ARMv5TEJ; | 
|  | 12784 | else if (0 == ::strcasecmp(arch_cstr, "armv5te"))   m_arm_isa = ARMv5TE; | 
|  | 12785 | else if (0 == ::strcasecmp(arch_cstr, "armv5t"))    m_arm_isa = ARMv5T; | 
|  | 12786 | else if (0 == ::strcasecmp(arch_cstr, "armv6k"))    m_arm_isa = ARMv6K; | 
|  | 12787 | else if (0 == ::strcasecmp(arch_cstr, "armv6"))     m_arm_isa = ARMv6; | 
|  | 12788 | else if (0 == ::strcasecmp(arch_cstr, "armv6t2"))   m_arm_isa = ARMv6T2; | 
|  | 12789 | else if (0 == ::strcasecmp(arch_cstr, "armv7"))     m_arm_isa = ARMv7; | 
|  | 12790 | else if (0 == ::strcasecmp(arch_cstr, "armv8"))     m_arm_isa = ARMv8; | 
| Johnny Chen | 1d29a85 | 2011-04-26 18:51:57 +0000 | [diff] [blame] | 12791 | else if (0 == ::strcasecmp(arch_cstr, "arm"))       m_arm_isa = ARMvAll; | 
|  | 12792 | else if (0 == ::strcasecmp(arch_cstr, "thumb"))     m_arm_isa = ARMvAll; | 
| Greg Clayton | 31e2a38 | 2011-01-30 20:03:56 +0000 | [diff] [blame] | 12793 | } | 
|  | 12794 | return m_arm_isa != 0; | 
|  | 12795 | } | 
|  | 12796 |  | 
| Caroline Tice | 080bf61 | 2011-04-05 18:46:00 +0000 | [diff] [blame] | 12797 | bool | 
| Greg Clayton | 888a733 | 2011-04-26 04:39:08 +0000 | [diff] [blame] | 12798 | EmulateInstructionARM::SetInstruction (const Opcode &insn_opcode, const Address &inst_addr, Target *target) | 
| Caroline Tice | 080bf61 | 2011-04-05 18:46:00 +0000 | [diff] [blame] | 12799 | { | 
| Greg Clayton | 888a733 | 2011-04-26 04:39:08 +0000 | [diff] [blame] | 12800 | if (EmulateInstruction::SetInstruction (insn_opcode, inst_addr, target)) | 
|  | 12801 | { | 
|  | 12802 | if (m_arch.GetTriple().getArch() == llvm::Triple::thumb) | 
|  | 12803 | m_opcode_mode = eModeThumb; | 
|  | 12804 | else | 
|  | 12805 | { | 
|  | 12806 | AddressClass addr_class = inst_addr.GetAddressClass(); | 
| Caroline Tice | 080bf61 | 2011-04-05 18:46:00 +0000 | [diff] [blame] | 12807 |  | 
| Greg Clayton | 888a733 | 2011-04-26 04:39:08 +0000 | [diff] [blame] | 12808 | if ((addr_class == eAddressClassCode) || (addr_class == eAddressClassUnknown)) | 
|  | 12809 | m_opcode_mode = eModeARM; | 
|  | 12810 | else if (addr_class == eAddressClassCodeAlternateISA) | 
|  | 12811 | m_opcode_mode = eModeThumb; | 
|  | 12812 | else | 
|  | 12813 | return false; | 
|  | 12814 | } | 
|  | 12815 | if (m_opcode_mode == eModeThumb) | 
|  | 12816 | m_opcode_cpsr = CPSR_MODE_USR | MASK_CPSR_T; | 
|  | 12817 | else | 
|  | 12818 | m_opcode_cpsr = CPSR_MODE_USR; | 
|  | 12819 | return true; | 
|  | 12820 | } | 
|  | 12821 | return false; | 
| Caroline Tice | 080bf61 | 2011-04-05 18:46:00 +0000 | [diff] [blame] | 12822 | } | 
| Greg Clayton | 31e2a38 | 2011-01-30 20:03:56 +0000 | [diff] [blame] | 12823 |  | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 12824 | bool | 
|  | 12825 | EmulateInstructionARM::ReadInstruction () | 
|  | 12826 | { | 
|  | 12827 | bool success = false; | 
| Greg Clayton | b344843 | 2011-03-24 21:19:54 +0000 | [diff] [blame] | 12828 | m_opcode_cpsr = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS, 0, &success); | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 12829 | if (success) | 
|  | 12830 | { | 
|  | 12831 | addr_t pc = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_ADDRESS, &success); | 
|  | 12832 | if (success) | 
|  | 12833 | { | 
| Caroline Tice | 9bfe7f2 | 2011-02-14 23:03:21 +0000 | [diff] [blame] | 12834 | Context read_inst_context; | 
|  | 12835 | read_inst_context.type = eContextReadOpcode; | 
|  | 12836 | read_inst_context.SetNoArgs (); | 
|  | 12837 |  | 
| Greg Clayton | b344843 | 2011-03-24 21:19:54 +0000 | [diff] [blame] | 12838 | if (m_opcode_cpsr & MASK_CPSR_T) | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 12839 | { | 
| Greg Clayton | b344843 | 2011-03-24 21:19:54 +0000 | [diff] [blame] | 12840 | m_opcode_mode = eModeThumb; | 
| Caroline Tice | cc96eb5 | 2011-02-17 19:20:40 +0000 | [diff] [blame] | 12841 | uint32_t thumb_opcode = MemARead(read_inst_context, pc, 2, 0, &success); | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 12842 |  | 
|  | 12843 | if (success) | 
|  | 12844 | { | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 12845 | if ((thumb_opcode & 0xe000) != 0xe000 || ((thumb_opcode & 0x1800u) == 0)) | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 12846 | { | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 12847 | m_opcode.SetOpcode16 (thumb_opcode); | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 12848 | } | 
|  | 12849 | else | 
|  | 12850 | { | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 12851 | m_opcode.SetOpcode32 ((thumb_opcode << 16) | MemARead(read_inst_context, pc + 2, 2, 0, &success)); | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 12852 | } | 
|  | 12853 | } | 
|  | 12854 | } | 
|  | 12855 | else | 
|  | 12856 | { | 
| Greg Clayton | b344843 | 2011-03-24 21:19:54 +0000 | [diff] [blame] | 12857 | m_opcode_mode = eModeARM; | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 12858 | m_opcode.SetOpcode32 (MemARead(read_inst_context, pc, 4, 0, &success)); | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 12859 | } | 
|  | 12860 | } | 
|  | 12861 | } | 
|  | 12862 | if (!success) | 
|  | 12863 | { | 
| Greg Clayton | b344843 | 2011-03-24 21:19:54 +0000 | [diff] [blame] | 12864 | m_opcode_mode = eModeInvalid; | 
| Greg Clayton | 3063c95 | 2011-04-29 22:50:31 +0000 | [diff] [blame] | 12865 | m_addr = LLDB_INVALID_ADDRESS; | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 12866 | } | 
|  | 12867 | return success; | 
|  | 12868 | } | 
|  | 12869 |  | 
| Johnny Chen | ee9b1f7 | 2011-02-09 01:00:31 +0000 | [diff] [blame] | 12870 | uint32_t | 
|  | 12871 | EmulateInstructionARM::ArchVersion () | 
|  | 12872 | { | 
|  | 12873 | return m_arm_isa; | 
|  | 12874 | } | 
|  | 12875 |  | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 12876 | bool | 
| Greg Clayton | 107e53d | 2011-07-06 04:07:21 +0000 | [diff] [blame] | 12877 | EmulateInstructionARM::ConditionPassed (const uint32_t opcode, bool *is_conditional) | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 12878 | { | 
| Greg Clayton | 888a733 | 2011-04-26 04:39:08 +0000 | [diff] [blame] | 12879 | // If we are ignoring conditions, then always return true. | 
|  | 12880 | // this allows us to iterate over disassembly code and still | 
|  | 12881 | // emulate an instruction even if we don't have all the right | 
|  | 12882 | // bits set in the CPSR register... | 
|  | 12883 | if (m_ignore_conditions) | 
|  | 12884 | return true; | 
| Greg Clayton | 107e53d | 2011-07-06 04:07:21 +0000 | [diff] [blame] | 12885 |  | 
|  | 12886 | if (is_conditional) | 
|  | 12887 | *is_conditional = true; | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 12888 |  | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 12889 | const uint32_t cond = CurrentCond (opcode); | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 12890 |  | 
|  | 12891 | if (cond == UINT32_MAX) | 
|  | 12892 | return false; | 
|  | 12893 |  | 
|  | 12894 | bool result = false; | 
|  | 12895 | switch (UnsignedBits(cond, 3, 1)) | 
|  | 12896 | { | 
| Caroline Tice | 080bf61 | 2011-04-05 18:46:00 +0000 | [diff] [blame] | 12897 | case 0: | 
|  | 12898 | if (m_opcode_cpsr == 0) | 
| Greg Clayton | 107e53d | 2011-07-06 04:07:21 +0000 | [diff] [blame] | 12899 | result = true; | 
|  | 12900 | else | 
|  | 12901 | result = (m_opcode_cpsr & MASK_CPSR_Z) != 0; | 
| Caroline Tice | 080bf61 | 2011-04-05 18:46:00 +0000 | [diff] [blame] | 12902 | break; | 
|  | 12903 | case 1: | 
| Greg Clayton | 107e53d | 2011-07-06 04:07:21 +0000 | [diff] [blame] | 12904 | if (m_opcode_cpsr == 0) | 
|  | 12905 | result = true; | 
|  | 12906 | else | 
|  | 12907 | result = (m_opcode_cpsr & MASK_CPSR_C) != 0; | 
| Caroline Tice | 080bf61 | 2011-04-05 18:46:00 +0000 | [diff] [blame] | 12908 | break; | 
|  | 12909 | case 2: | 
| Greg Clayton | 107e53d | 2011-07-06 04:07:21 +0000 | [diff] [blame] | 12910 | if (m_opcode_cpsr == 0) | 
|  | 12911 | result = true; | 
|  | 12912 | else | 
|  | 12913 | result = (m_opcode_cpsr & MASK_CPSR_N) != 0; | 
| Caroline Tice | 080bf61 | 2011-04-05 18:46:00 +0000 | [diff] [blame] | 12914 | break; | 
|  | 12915 | case 3: | 
| Greg Clayton | 107e53d | 2011-07-06 04:07:21 +0000 | [diff] [blame] | 12916 | if (m_opcode_cpsr == 0) | 
|  | 12917 | result = true; | 
|  | 12918 | else | 
|  | 12919 | result = (m_opcode_cpsr & MASK_CPSR_V) != 0; | 
| Caroline Tice | 080bf61 | 2011-04-05 18:46:00 +0000 | [diff] [blame] | 12920 | break; | 
|  | 12921 | case 4: | 
| Greg Clayton | 107e53d | 2011-07-06 04:07:21 +0000 | [diff] [blame] | 12922 | if (m_opcode_cpsr == 0) | 
|  | 12923 | result = true; | 
|  | 12924 | else | 
|  | 12925 | result = ((m_opcode_cpsr & MASK_CPSR_C) != 0) && ((m_opcode_cpsr & MASK_CPSR_Z) == 0); | 
| Caroline Tice | 080bf61 | 2011-04-05 18:46:00 +0000 | [diff] [blame] | 12926 | break; | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 12927 | case 5: | 
| Greg Clayton | 107e53d | 2011-07-06 04:07:21 +0000 | [diff] [blame] | 12928 | if (m_opcode_cpsr == 0) | 
|  | 12929 | result = true; | 
|  | 12930 | else | 
| Caroline Tice | 080bf61 | 2011-04-05 18:46:00 +0000 | [diff] [blame] | 12931 | { | 
| Greg Clayton | b344843 | 2011-03-24 21:19:54 +0000 | [diff] [blame] | 12932 | bool n = (m_opcode_cpsr & MASK_CPSR_N); | 
|  | 12933 | bool v = (m_opcode_cpsr & MASK_CPSR_V); | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 12934 | result = n == v; | 
|  | 12935 | } | 
|  | 12936 | break; | 
|  | 12937 | case 6: | 
| Greg Clayton | 107e53d | 2011-07-06 04:07:21 +0000 | [diff] [blame] | 12938 | if (m_opcode_cpsr == 0) | 
|  | 12939 | result = true; | 
|  | 12940 | else | 
| Caroline Tice | 080bf61 | 2011-04-05 18:46:00 +0000 | [diff] [blame] | 12941 | { | 
| Greg Clayton | b344843 | 2011-03-24 21:19:54 +0000 | [diff] [blame] | 12942 | bool n = (m_opcode_cpsr & MASK_CPSR_N); | 
|  | 12943 | bool v = (m_opcode_cpsr & MASK_CPSR_V); | 
|  | 12944 | result = n == v && ((m_opcode_cpsr & MASK_CPSR_Z) == 0); | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 12945 | } | 
|  | 12946 | break; | 
|  | 12947 | case 7: | 
| Greg Clayton | 107e53d | 2011-07-06 04:07:21 +0000 | [diff] [blame] | 12948 | // Always execute (cond == 0b1110, or the special 0b1111 which gives | 
|  | 12949 | // opcodes different meanings, but always means execution happpens. | 
|  | 12950 | if (is_conditional) | 
|  | 12951 | *is_conditional = false; | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 12952 | result = true; | 
|  | 12953 | break; | 
|  | 12954 | } | 
|  | 12955 |  | 
|  | 12956 | if (cond & 1) | 
|  | 12957 | result = !result; | 
|  | 12958 | return result; | 
|  | 12959 | } | 
|  | 12960 |  | 
| Johnny Chen | 9ee056b | 2011-02-08 00:06:35 +0000 | [diff] [blame] | 12961 | uint32_t | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 12962 | EmulateInstructionARM::CurrentCond (const uint32_t opcode) | 
| Johnny Chen | 9ee056b | 2011-02-08 00:06:35 +0000 | [diff] [blame] | 12963 | { | 
| Greg Clayton | b344843 | 2011-03-24 21:19:54 +0000 | [diff] [blame] | 12964 | switch (m_opcode_mode) | 
| Johnny Chen | 9ee056b | 2011-02-08 00:06:35 +0000 | [diff] [blame] | 12965 | { | 
|  | 12966 | default: | 
|  | 12967 | case eModeInvalid: | 
|  | 12968 | break; | 
|  | 12969 |  | 
|  | 12970 | case eModeARM: | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 12971 | return UnsignedBits(opcode, 31, 28); | 
| Johnny Chen | 9ee056b | 2011-02-08 00:06:35 +0000 | [diff] [blame] | 12972 |  | 
|  | 12973 | case eModeThumb: | 
|  | 12974 | // For T1 and T3 encodings of the Branch instruction, it returns the 4-bit | 
|  | 12975 | // 'cond' field of the encoding. | 
| Johnny Chen | 9ee056b | 2011-02-08 00:06:35 +0000 | [diff] [blame] | 12976 | { | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 12977 | const uint32_t byte_size = m_opcode.GetByteSize(); | 
|  | 12978 | if (byte_size == 2) | 
|  | 12979 | { | 
|  | 12980 | if (Bits32(opcode, 15, 12) == 0x0d && Bits32(opcode, 11, 7) != 0x0f) | 
|  | 12981 | return Bits32(opcode, 11, 7); | 
|  | 12982 | } | 
| Johnny Chen | 6dc5a1a | 2011-06-02 23:19:06 +0000 | [diff] [blame] | 12983 | else if (byte_size == 4) | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 12984 | { | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 12985 | if (Bits32(opcode, 31, 27) == 0x1e && | 
|  | 12986 | Bits32(opcode, 15, 14) == 0x02 && | 
|  | 12987 | Bits32(opcode, 12, 12) == 0x00 && | 
|  | 12988 | Bits32(opcode, 25, 22) <= 0x0d) | 
|  | 12989 | { | 
|  | 12990 | return Bits32(opcode, 25, 22); | 
|  | 12991 | } | 
|  | 12992 | } | 
| Johnny Chen | 6dc5a1a | 2011-06-02 23:19:06 +0000 | [diff] [blame] | 12993 | else | 
|  | 12994 | // We have an invalid thumb instruction, let's bail out. | 
|  | 12995 | break; | 
| Greg Clayton | 7bc3908 | 2011-03-24 23:53:38 +0000 | [diff] [blame] | 12996 |  | 
|  | 12997 | return m_it_session.GetCond(); | 
| Johnny Chen | 9ee056b | 2011-02-08 00:06:35 +0000 | [diff] [blame] | 12998 | } | 
| Johnny Chen | 9ee056b | 2011-02-08 00:06:35 +0000 | [diff] [blame] | 12999 | } | 
|  | 13000 | return UINT32_MAX;  // Return invalid value | 
|  | 13001 | } | 
|  | 13002 |  | 
| Johnny Chen | 9ee056b | 2011-02-08 00:06:35 +0000 | [diff] [blame] | 13003 | bool | 
| Johnny Chen | 098ae2d | 2011-02-12 00:50:05 +0000 | [diff] [blame] | 13004 | EmulateInstructionARM::InITBlock() | 
|  | 13005 | { | 
|  | 13006 | return CurrentInstrSet() == eModeThumb && m_it_session.InITBlock(); | 
|  | 13007 | } | 
|  | 13008 |  | 
|  | 13009 | bool | 
|  | 13010 | EmulateInstructionARM::LastInITBlock() | 
|  | 13011 | { | 
|  | 13012 | return CurrentInstrSet() == eModeThumb && m_it_session.LastInITBlock(); | 
|  | 13013 | } | 
|  | 13014 |  | 
| Caroline Tice | b27771d | 2011-03-03 22:37:46 +0000 | [diff] [blame] | 13015 | bool | 
|  | 13016 | EmulateInstructionARM::BadMode (uint32_t mode) | 
|  | 13017 | { | 
|  | 13018 |  | 
|  | 13019 | switch (mode) | 
|  | 13020 | { | 
|  | 13021 | case 16: return false; // '10000' | 
|  | 13022 | case 17: return false; // '10001' | 
|  | 13023 | case 18: return false; // '10010' | 
|  | 13024 | case 19: return false; // '10011' | 
|  | 13025 | case 22: return false; // '10110' | 
|  | 13026 | case 23: return false; // '10111' | 
|  | 13027 | case 27: return false; // '11011' | 
|  | 13028 | case 31: return false; // '11111' | 
|  | 13029 | default: return true; | 
|  | 13030 | } | 
|  | 13031 | return true; | 
|  | 13032 | } | 
|  | 13033 |  | 
|  | 13034 | bool | 
|  | 13035 | EmulateInstructionARM::CurrentModeIsPrivileged () | 
|  | 13036 | { | 
| Greg Clayton | b344843 | 2011-03-24 21:19:54 +0000 | [diff] [blame] | 13037 | uint32_t mode = Bits32 (m_opcode_cpsr, 4, 0); | 
| Caroline Tice | b27771d | 2011-03-03 22:37:46 +0000 | [diff] [blame] | 13038 |  | 
|  | 13039 | if (BadMode (mode)) | 
|  | 13040 | return false; | 
|  | 13041 |  | 
|  | 13042 | if (mode == 16) | 
| Greg Clayton | 888a733 | 2011-04-26 04:39:08 +0000 | [diff] [blame] | 13043 | return false; | 
| Caroline Tice | b27771d | 2011-03-03 22:37:46 +0000 | [diff] [blame] | 13044 |  | 
|  | 13045 | return true; | 
|  | 13046 | } | 
|  | 13047 |  | 
|  | 13048 | void | 
|  | 13049 | EmulateInstructionARM::CPSRWriteByInstr (uint32_t value, uint32_t bytemask, bool affect_execstate) | 
|  | 13050 | { | 
|  | 13051 | bool privileged = CurrentModeIsPrivileged(); | 
|  | 13052 |  | 
| Johnny Chen | 65f39ed | 2011-08-12 01:10:45 +0000 | [diff] [blame] | 13053 | uint32_t tmp_cpsr = Bits32 (m_opcode_cpsr, 23, 20) << 20; | 
| Caroline Tice | b27771d | 2011-03-03 22:37:46 +0000 | [diff] [blame] | 13054 |  | 
|  | 13055 | if (BitIsSet (bytemask, 3)) | 
|  | 13056 | { | 
|  | 13057 | tmp_cpsr = tmp_cpsr | (Bits32 (value, 31, 27) << 27); | 
|  | 13058 | if (affect_execstate) | 
|  | 13059 | tmp_cpsr = tmp_cpsr | (Bits32 (value, 26, 24) << 24); | 
|  | 13060 | } | 
|  | 13061 |  | 
|  | 13062 | if (BitIsSet (bytemask, 2)) | 
|  | 13063 | { | 
|  | 13064 | tmp_cpsr = tmp_cpsr | (Bits32 (value, 19, 16) << 16); | 
|  | 13065 | } | 
|  | 13066 |  | 
|  | 13067 | if (BitIsSet (bytemask, 1)) | 
|  | 13068 | { | 
|  | 13069 | if (affect_execstate) | 
|  | 13070 | tmp_cpsr = tmp_cpsr | (Bits32 (value, 15, 10) << 10); | 
|  | 13071 | tmp_cpsr = tmp_cpsr | (Bit32 (value, 9) << 9); | 
|  | 13072 | if (privileged) | 
|  | 13073 | tmp_cpsr = tmp_cpsr | (Bit32 (value, 8) << 8); | 
|  | 13074 | } | 
|  | 13075 |  | 
|  | 13076 | if (BitIsSet (bytemask, 0)) | 
|  | 13077 | { | 
|  | 13078 | if (privileged) | 
|  | 13079 | tmp_cpsr = tmp_cpsr | (Bits32 (value, 7, 6) << 6); | 
|  | 13080 | if (affect_execstate) | 
|  | 13081 | tmp_cpsr = tmp_cpsr | (Bit32 (value, 5) << 5); | 
|  | 13082 | if (privileged) | 
|  | 13083 | tmp_cpsr = tmp_cpsr | Bits32 (value, 4, 0); | 
|  | 13084 | } | 
|  | 13085 |  | 
| Greg Clayton | b344843 | 2011-03-24 21:19:54 +0000 | [diff] [blame] | 13086 | m_opcode_cpsr = tmp_cpsr; | 
| Caroline Tice | b27771d | 2011-03-03 22:37:46 +0000 | [diff] [blame] | 13087 | } | 
|  | 13088 |  | 
|  | 13089 |  | 
| Johnny Chen | 098ae2d | 2011-02-12 00:50:05 +0000 | [diff] [blame] | 13090 | bool | 
| Johnny Chen | 9ee056b | 2011-02-08 00:06:35 +0000 | [diff] [blame] | 13091 | EmulateInstructionARM::BranchWritePC (const Context &context, uint32_t addr) | 
|  | 13092 | { | 
|  | 13093 | addr_t target; | 
|  | 13094 |  | 
| Johnny Chen | ee9b1f7 | 2011-02-09 01:00:31 +0000 | [diff] [blame] | 13095 | // Check the current instruction set. | 
|  | 13096 | if (CurrentInstrSet() == eModeARM) | 
| Johnny Chen | 9ee056b | 2011-02-08 00:06:35 +0000 | [diff] [blame] | 13097 | target = addr & 0xfffffffc; | 
| Johnny Chen | ee9b1f7 | 2011-02-09 01:00:31 +0000 | [diff] [blame] | 13098 | else | 
| Johnny Chen | 9ee056b | 2011-02-08 00:06:35 +0000 | [diff] [blame] | 13099 | target = addr & 0xfffffffe; | 
| Johnny Chen | ee9b1f7 | 2011-02-09 01:00:31 +0000 | [diff] [blame] | 13100 |  | 
| Johnny Chen | 9ee056b | 2011-02-08 00:06:35 +0000 | [diff] [blame] | 13101 | if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, target)) | 
| Johnny Chen | 53ebab7 | 2011-02-08 23:21:57 +0000 | [diff] [blame] | 13102 | return false; | 
|  | 13103 |  | 
|  | 13104 | return true; | 
| Johnny Chen | 9ee056b | 2011-02-08 00:06:35 +0000 | [diff] [blame] | 13105 | } | 
|  | 13106 |  | 
|  | 13107 | // As a side effect, BXWritePC sets context.arg2 to eModeARM or eModeThumb by inspecting addr. | 
|  | 13108 | bool | 
| Johnny Chen | 668b451 | 2011-02-15 21:08:58 +0000 | [diff] [blame] | 13109 | EmulateInstructionARM::BXWritePC (Context &context, uint32_t addr) | 
| Johnny Chen | 9ee056b | 2011-02-08 00:06:35 +0000 | [diff] [blame] | 13110 | { | 
|  | 13111 | addr_t target; | 
| Johnny Chen | 0f309db | 2011-02-09 19:11:32 +0000 | [diff] [blame] | 13112 | // If the CPSR is changed due to switching between ARM and Thumb ISETSTATE, | 
|  | 13113 | // we want to record it and issue a WriteRegister callback so the clients | 
|  | 13114 | // can track the mode changes accordingly. | 
|  | 13115 | bool cpsr_changed = false; | 
| Johnny Chen | 9ee056b | 2011-02-08 00:06:35 +0000 | [diff] [blame] | 13116 |  | 
|  | 13117 | if (BitIsSet(addr, 0)) | 
|  | 13118 | { | 
| Johnny Chen | 0f309db | 2011-02-09 19:11:32 +0000 | [diff] [blame] | 13119 | if (CurrentInstrSet() != eModeThumb) | 
|  | 13120 | { | 
|  | 13121 | SelectInstrSet(eModeThumb); | 
|  | 13122 | cpsr_changed = true; | 
|  | 13123 | } | 
| Johnny Chen | 9ee056b | 2011-02-08 00:06:35 +0000 | [diff] [blame] | 13124 | target = addr & 0xfffffffe; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 13125 | context.SetISA (eModeThumb); | 
| Johnny Chen | 9ee056b | 2011-02-08 00:06:35 +0000 | [diff] [blame] | 13126 | } | 
|  | 13127 | else if (BitIsClear(addr, 1)) | 
|  | 13128 | { | 
| Johnny Chen | 0f309db | 2011-02-09 19:11:32 +0000 | [diff] [blame] | 13129 | if (CurrentInstrSet() != eModeARM) | 
|  | 13130 | { | 
|  | 13131 | SelectInstrSet(eModeARM); | 
|  | 13132 | cpsr_changed = true; | 
|  | 13133 | } | 
| Johnny Chen | 9ee056b | 2011-02-08 00:06:35 +0000 | [diff] [blame] | 13134 | target = addr & 0xfffffffc; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 13135 | context.SetISA (eModeARM); | 
| Johnny Chen | 9ee056b | 2011-02-08 00:06:35 +0000 | [diff] [blame] | 13136 | } | 
|  | 13137 | else | 
|  | 13138 | return false; // address<1:0> == '10' => UNPREDICTABLE | 
|  | 13139 |  | 
| Johnny Chen | 0f309db | 2011-02-09 19:11:32 +0000 | [diff] [blame] | 13140 | if (cpsr_changed) | 
|  | 13141 | { | 
| Johnny Chen | 558133b | 2011-02-09 23:59:17 +0000 | [diff] [blame] | 13142 | if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS, m_new_inst_cpsr)) | 
| Johnny Chen | 0f309db | 2011-02-09 19:11:32 +0000 | [diff] [blame] | 13143 | return false; | 
|  | 13144 | } | 
| Johnny Chen | 9ee056b | 2011-02-08 00:06:35 +0000 | [diff] [blame] | 13145 | if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, target)) | 
| Johnny Chen | 53ebab7 | 2011-02-08 23:21:57 +0000 | [diff] [blame] | 13146 | return false; | 
|  | 13147 |  | 
|  | 13148 | return true; | 
| Johnny Chen | 9ee056b | 2011-02-08 00:06:35 +0000 | [diff] [blame] | 13149 | } | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 13150 |  | 
| Johnny Chen | ee9b1f7 | 2011-02-09 01:00:31 +0000 | [diff] [blame] | 13151 | // Dispatches to either BXWritePC or BranchWritePC based on architecture versions. | 
|  | 13152 | bool | 
| Johnny Chen | 668b451 | 2011-02-15 21:08:58 +0000 | [diff] [blame] | 13153 | EmulateInstructionARM::LoadWritePC (Context &context, uint32_t addr) | 
| Johnny Chen | ee9b1f7 | 2011-02-09 01:00:31 +0000 | [diff] [blame] | 13154 | { | 
|  | 13155 | if (ArchVersion() >= ARMv5T) | 
| Johnny Chen | 668b451 | 2011-02-15 21:08:58 +0000 | [diff] [blame] | 13156 | return BXWritePC(context, addr); | 
| Johnny Chen | ee9b1f7 | 2011-02-09 01:00:31 +0000 | [diff] [blame] | 13157 | else | 
|  | 13158 | return BranchWritePC((const Context)context, addr); | 
|  | 13159 | } | 
|  | 13160 |  | 
| Johnny Chen | 26863dc | 2011-02-09 23:43:29 +0000 | [diff] [blame] | 13161 | // Dispatches to either BXWritePC or BranchWritePC based on architecture versions and current instruction set. | 
|  | 13162 | bool | 
| Johnny Chen | 668b451 | 2011-02-15 21:08:58 +0000 | [diff] [blame] | 13163 | EmulateInstructionARM::ALUWritePC (Context &context, uint32_t addr) | 
| Johnny Chen | 26863dc | 2011-02-09 23:43:29 +0000 | [diff] [blame] | 13164 | { | 
|  | 13165 | if (ArchVersion() >= ARMv7 && CurrentInstrSet() == eModeARM) | 
| Johnny Chen | 668b451 | 2011-02-15 21:08:58 +0000 | [diff] [blame] | 13166 | return BXWritePC(context, addr); | 
| Johnny Chen | 26863dc | 2011-02-09 23:43:29 +0000 | [diff] [blame] | 13167 | else | 
|  | 13168 | return BranchWritePC((const Context)context, addr); | 
|  | 13169 | } | 
|  | 13170 |  | 
| Johnny Chen | ee9b1f7 | 2011-02-09 01:00:31 +0000 | [diff] [blame] | 13171 | EmulateInstructionARM::Mode | 
|  | 13172 | EmulateInstructionARM::CurrentInstrSet () | 
|  | 13173 | { | 
| Greg Clayton | b344843 | 2011-03-24 21:19:54 +0000 | [diff] [blame] | 13174 | return m_opcode_mode; | 
| Johnny Chen | ee9b1f7 | 2011-02-09 01:00:31 +0000 | [diff] [blame] | 13175 | } | 
|  | 13176 |  | 
| Greg Clayton | b344843 | 2011-03-24 21:19:54 +0000 | [diff] [blame] | 13177 | // Set the 'T' bit of our CPSR.  The m_opcode_mode gets updated when the next | 
| Johnny Chen | 558133b | 2011-02-09 23:59:17 +0000 | [diff] [blame] | 13178 | // ReadInstruction() is performed.  This function has a side effect of updating | 
|  | 13179 | // the m_new_inst_cpsr member variable if necessary. | 
| Johnny Chen | ee9b1f7 | 2011-02-09 01:00:31 +0000 | [diff] [blame] | 13180 | bool | 
|  | 13181 | EmulateInstructionARM::SelectInstrSet (Mode arm_or_thumb) | 
|  | 13182 | { | 
| Greg Clayton | b344843 | 2011-03-24 21:19:54 +0000 | [diff] [blame] | 13183 | m_new_inst_cpsr = m_opcode_cpsr; | 
| Johnny Chen | ee9b1f7 | 2011-02-09 01:00:31 +0000 | [diff] [blame] | 13184 | switch (arm_or_thumb) | 
|  | 13185 | { | 
|  | 13186 | default: | 
|  | 13187 | return false; | 
|  | 13188 | eModeARM: | 
|  | 13189 | // Clear the T bit. | 
| Johnny Chen | 558133b | 2011-02-09 23:59:17 +0000 | [diff] [blame] | 13190 | m_new_inst_cpsr &= ~MASK_CPSR_T; | 
| Johnny Chen | ee9b1f7 | 2011-02-09 01:00:31 +0000 | [diff] [blame] | 13191 | break; | 
|  | 13192 | eModeThumb: | 
|  | 13193 | // Set the T bit. | 
| Johnny Chen | 558133b | 2011-02-09 23:59:17 +0000 | [diff] [blame] | 13194 | m_new_inst_cpsr |= MASK_CPSR_T; | 
| Johnny Chen | ee9b1f7 | 2011-02-09 01:00:31 +0000 | [diff] [blame] | 13195 | break; | 
|  | 13196 | } | 
|  | 13197 | return true; | 
|  | 13198 | } | 
|  | 13199 |  | 
| Johnny Chen | ef21b59 | 2011-02-10 01:52:38 +0000 | [diff] [blame] | 13200 | // This function returns TRUE if the processor currently provides support for | 
|  | 13201 | // unaligned memory accesses, or FALSE otherwise. This is always TRUE in ARMv7, | 
|  | 13202 | // controllable by the SCTLR.U bit in ARMv6, and always FALSE before ARMv6. | 
|  | 13203 | bool | 
|  | 13204 | EmulateInstructionARM::UnalignedSupport() | 
|  | 13205 | { | 
|  | 13206 | return (ArchVersion() >= ARMv7); | 
|  | 13207 | } | 
|  | 13208 |  | 
| Johnny Chen | bf6ad17 | 2011-02-11 01:29:53 +0000 | [diff] [blame] | 13209 | // The main addition and subtraction instructions can produce status information | 
|  | 13210 | // about both unsigned carry and signed overflow conditions.  This status | 
|  | 13211 | // information can be used to synthesize multi-word additions and subtractions. | 
|  | 13212 | EmulateInstructionARM::AddWithCarryResult | 
|  | 13213 | EmulateInstructionARM::AddWithCarry (uint32_t x, uint32_t y, uint8_t carry_in) | 
|  | 13214 | { | 
|  | 13215 | uint32_t result; | 
|  | 13216 | uint8_t carry_out; | 
|  | 13217 | uint8_t overflow; | 
|  | 13218 |  | 
|  | 13219 | uint64_t unsigned_sum = x + y + carry_in; | 
|  | 13220 | int64_t signed_sum = (int32_t)x + (int32_t)y + (int32_t)carry_in; | 
|  | 13221 |  | 
|  | 13222 | result = UnsignedBits(unsigned_sum, 31, 0); | 
| Caroline Tice | 0fe5a53 | 2011-04-08 23:33:06 +0000 | [diff] [blame] | 13223 | //    carry_out = (result == unsigned_sum ? 0 : 1); | 
| Johnny Chen | bf6ad17 | 2011-02-11 01:29:53 +0000 | [diff] [blame] | 13224 | overflow = ((int32_t)result == signed_sum ? 0 : 1); | 
| Caroline Tice | 0fe5a53 | 2011-04-08 23:33:06 +0000 | [diff] [blame] | 13225 |  | 
|  | 13226 | if (carry_in) | 
| Caroline Tice | 523c554 | 2011-04-13 00:42:12 +0000 | [diff] [blame] | 13227 | carry_out = ((int32_t) x >= (int32_t) (~y)) ? 1 : 0; | 
| Caroline Tice | 0fe5a53 | 2011-04-08 23:33:06 +0000 | [diff] [blame] | 13228 | else | 
|  | 13229 | carry_out = ((int32_t) x > (int32_t) y) ? 1 : 0; | 
| Johnny Chen | bf6ad17 | 2011-02-11 01:29:53 +0000 | [diff] [blame] | 13230 |  | 
|  | 13231 | AddWithCarryResult res = { result, carry_out, overflow }; | 
|  | 13232 | return res; | 
|  | 13233 | } | 
|  | 13234 |  | 
| Johnny Chen | 157b959 | 2011-02-18 21:13:05 +0000 | [diff] [blame] | 13235 | uint32_t | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 13236 | EmulateInstructionARM::ReadCoreReg(uint32_t num, bool *success) | 
| Johnny Chen | 157b959 | 2011-02-18 21:13:05 +0000 | [diff] [blame] | 13237 | { | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 13238 | uint32_t reg_kind, reg_num; | 
|  | 13239 | switch (num) | 
| Johnny Chen | 157b959 | 2011-02-18 21:13:05 +0000 | [diff] [blame] | 13240 | { | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 13241 | case SP_REG: | 
|  | 13242 | reg_kind = eRegisterKindGeneric; | 
|  | 13243 | reg_num  = LLDB_REGNUM_GENERIC_SP; | 
|  | 13244 | break; | 
|  | 13245 | case LR_REG: | 
|  | 13246 | reg_kind = eRegisterKindGeneric; | 
|  | 13247 | reg_num  = LLDB_REGNUM_GENERIC_RA; | 
|  | 13248 | break; | 
|  | 13249 | case PC_REG: | 
|  | 13250 | reg_kind = eRegisterKindGeneric; | 
|  | 13251 | reg_num  = LLDB_REGNUM_GENERIC_PC; | 
|  | 13252 | break; | 
|  | 13253 | default: | 
| Greg Clayton | 4fdf760 | 2011-03-20 04:57:14 +0000 | [diff] [blame] | 13254 | if (num < SP_REG) | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 13255 | { | 
|  | 13256 | reg_kind = eRegisterKindDWARF; | 
|  | 13257 | reg_num  = dwarf_r0 + num; | 
|  | 13258 | } | 
| Johnny Chen | 157b959 | 2011-02-18 21:13:05 +0000 | [diff] [blame] | 13259 | else | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 13260 | { | 
| Greg Clayton | e1f47bb | 2011-06-02 22:23:35 +0000 | [diff] [blame] | 13261 | //assert(0 && "Invalid register number"); | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 13262 | *success = false; | 
| Greg Clayton | 4fdf760 | 2011-03-20 04:57:14 +0000 | [diff] [blame] | 13263 | return UINT32_MAX; | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 13264 | } | 
|  | 13265 | break; | 
| Johnny Chen | 157b959 | 2011-02-18 21:13:05 +0000 | [diff] [blame] | 13266 | } | 
| Johnny Chen | e39f22d | 2011-02-19 01:36:13 +0000 | [diff] [blame] | 13267 |  | 
|  | 13268 | // Read our register. | 
|  | 13269 | uint32_t val = ReadRegisterUnsigned (reg_kind, reg_num, 0, success); | 
|  | 13270 |  | 
|  | 13271 | // When executing an ARM instruction , PC reads as the address of the current | 
|  | 13272 | // instruction plus 8. | 
|  | 13273 | // When executing a Thumb instruction , PC reads as the address of the current | 
|  | 13274 | // instruction plus 4. | 
|  | 13275 | if (num == 15) | 
|  | 13276 | { | 
|  | 13277 | if (CurrentInstrSet() == eModeARM) | 
|  | 13278 | val += 8; | 
|  | 13279 | else | 
|  | 13280 | val += 4; | 
|  | 13281 | } | 
| Johnny Chen | 157b959 | 2011-02-18 21:13:05 +0000 | [diff] [blame] | 13282 |  | 
|  | 13283 | return val; | 
|  | 13284 | } | 
|  | 13285 |  | 
| Johnny Chen | ca67d1c | 2011-02-17 01:35:27 +0000 | [diff] [blame] | 13286 | // Write the result to the ARM core register Rd, and optionally update the | 
|  | 13287 | // condition flags based on the result. | 
|  | 13288 | // | 
|  | 13289 | // This helper method tries to encapsulate the following pseudocode from the | 
|  | 13290 | // ARM Architecture Reference Manual: | 
|  | 13291 | // | 
|  | 13292 | // if d == 15 then         // Can only occur for encoding A1 | 
|  | 13293 | //     ALUWritePC(result); // setflags is always FALSE here | 
|  | 13294 | // else | 
|  | 13295 | //     R[d] = result; | 
|  | 13296 | //     if setflags then | 
|  | 13297 | //         APSR.N = result<31>; | 
|  | 13298 | //         APSR.Z = IsZeroBit(result); | 
|  | 13299 | //         APSR.C = carry; | 
|  | 13300 | //         // APSR.V unchanged | 
|  | 13301 | // | 
|  | 13302 | // In the above case, the API client does not pass in the overflow arg, which | 
|  | 13303 | // defaults to ~0u. | 
|  | 13304 | bool | 
| Johnny Chen | 10530c2 | 2011-02-17 22:37:12 +0000 | [diff] [blame] | 13305 | EmulateInstructionARM::WriteCoreRegOptionalFlags (Context &context, | 
|  | 13306 | const uint32_t result, | 
|  | 13307 | const uint32_t Rd, | 
|  | 13308 | bool setflags, | 
|  | 13309 | const uint32_t carry, | 
|  | 13310 | const uint32_t overflow) | 
| Johnny Chen | ca67d1c | 2011-02-17 01:35:27 +0000 | [diff] [blame] | 13311 | { | 
|  | 13312 | if (Rd == 15) | 
|  | 13313 | { | 
|  | 13314 | if (!ALUWritePC (context, result)) | 
|  | 13315 | return false; | 
|  | 13316 | } | 
|  | 13317 | else | 
|  | 13318 | { | 
| Johnny Chen | a695f95 | 2011-02-23 21:24:25 +0000 | [diff] [blame] | 13319 | uint32_t reg_kind, reg_num; | 
|  | 13320 | switch (Rd) | 
|  | 13321 | { | 
|  | 13322 | case SP_REG: | 
|  | 13323 | reg_kind = eRegisterKindGeneric; | 
|  | 13324 | reg_num  = LLDB_REGNUM_GENERIC_SP; | 
|  | 13325 | break; | 
|  | 13326 | case LR_REG: | 
|  | 13327 | reg_kind = eRegisterKindGeneric; | 
|  | 13328 | reg_num  = LLDB_REGNUM_GENERIC_RA; | 
|  | 13329 | break; | 
|  | 13330 | default: | 
|  | 13331 | reg_kind = eRegisterKindDWARF; | 
|  | 13332 | reg_num  = dwarf_r0 + Rd; | 
|  | 13333 | } | 
|  | 13334 | if (!WriteRegisterUnsigned (context, reg_kind, reg_num, result)) | 
| Johnny Chen | ca67d1c | 2011-02-17 01:35:27 +0000 | [diff] [blame] | 13335 | return false; | 
|  | 13336 | if (setflags) | 
| Johnny Chen | 10530c2 | 2011-02-17 22:37:12 +0000 | [diff] [blame] | 13337 | return WriteFlags (context, result, carry, overflow); | 
|  | 13338 | } | 
|  | 13339 | return true; | 
|  | 13340 | } | 
|  | 13341 |  | 
|  | 13342 | // This helper method tries to encapsulate the following pseudocode from the | 
|  | 13343 | // ARM Architecture Reference Manual: | 
|  | 13344 | // | 
|  | 13345 | // APSR.N = result<31>; | 
|  | 13346 | // APSR.Z = IsZeroBit(result); | 
|  | 13347 | // APSR.C = carry; | 
|  | 13348 | // APSR.V = overflow | 
|  | 13349 | // | 
|  | 13350 | // Default arguments can be specified for carry and overflow parameters, which means | 
|  | 13351 | // not to update the respective flags. | 
|  | 13352 | bool | 
|  | 13353 | EmulateInstructionARM::WriteFlags (Context &context, | 
|  | 13354 | const uint32_t result, | 
|  | 13355 | const uint32_t carry, | 
|  | 13356 | const uint32_t overflow) | 
|  | 13357 | { | 
| Greg Clayton | b344843 | 2011-03-24 21:19:54 +0000 | [diff] [blame] | 13358 | m_new_inst_cpsr = m_opcode_cpsr; | 
| Johnny Chen | 2434884 | 2011-02-23 00:15:56 +0000 | [diff] [blame] | 13359 | SetBit32(m_new_inst_cpsr, CPSR_N_POS, Bit32(result, CPSR_N_POS)); | 
|  | 13360 | SetBit32(m_new_inst_cpsr, CPSR_Z_POS, result == 0 ? 1 : 0); | 
| Johnny Chen | 10530c2 | 2011-02-17 22:37:12 +0000 | [diff] [blame] | 13361 | if (carry != ~0u) | 
| Johnny Chen | 2434884 | 2011-02-23 00:15:56 +0000 | [diff] [blame] | 13362 | SetBit32(m_new_inst_cpsr, CPSR_C_POS, carry); | 
| Johnny Chen | 10530c2 | 2011-02-17 22:37:12 +0000 | [diff] [blame] | 13363 | if (overflow != ~0u) | 
| Johnny Chen | 2434884 | 2011-02-23 00:15:56 +0000 | [diff] [blame] | 13364 | SetBit32(m_new_inst_cpsr, CPSR_V_POS, overflow); | 
| Greg Clayton | b344843 | 2011-03-24 21:19:54 +0000 | [diff] [blame] | 13365 | if (m_new_inst_cpsr != m_opcode_cpsr) | 
| Johnny Chen | 10530c2 | 2011-02-17 22:37:12 +0000 | [diff] [blame] | 13366 | { | 
|  | 13367 | if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS, m_new_inst_cpsr)) | 
|  | 13368 | return false; | 
| Johnny Chen | ca67d1c | 2011-02-17 01:35:27 +0000 | [diff] [blame] | 13369 | } | 
|  | 13370 | return true; | 
|  | 13371 | } | 
|  | 13372 |  | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 13373 | bool | 
| Greg Clayton | 888a733 | 2011-04-26 04:39:08 +0000 | [diff] [blame] | 13374 | EmulateInstructionARM::EvaluateInstruction (uint32_t evaluate_options) | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 13375 | { | 
| Johnny Chen | c315f86 | 2011-02-05 00:46:10 +0000 | [diff] [blame] | 13376 | // Advance the ITSTATE bits to their values for the next instruction. | 
| Greg Clayton | b344843 | 2011-03-24 21:19:54 +0000 | [diff] [blame] | 13377 | if (m_opcode_mode == eModeThumb && m_it_session.InITBlock()) | 
| Johnny Chen | c315f86 | 2011-02-05 00:46:10 +0000 | [diff] [blame] | 13378 | m_it_session.ITAdvance(); | 
|  | 13379 |  | 
| Greg Clayton | 888a733 | 2011-04-26 04:39:08 +0000 | [diff] [blame] | 13380 | ARMOpcode *opcode_data = NULL; | 
| Caroline Tice | 080bf61 | 2011-04-05 18:46:00 +0000 | [diff] [blame] | 13381 |  | 
|  | 13382 | if (m_opcode_mode == eModeThumb) | 
| Greg Clayton | 888a733 | 2011-04-26 04:39:08 +0000 | [diff] [blame] | 13383 | opcode_data = GetThumbOpcodeForInstruction (m_opcode.GetOpcode32(), m_arm_isa); | 
| Caroline Tice | 080bf61 | 2011-04-05 18:46:00 +0000 | [diff] [blame] | 13384 | else if (m_opcode_mode == eModeARM) | 
| Greg Clayton | 888a733 | 2011-04-26 04:39:08 +0000 | [diff] [blame] | 13385 | opcode_data = GetARMOpcodeForInstruction (m_opcode.GetOpcode32(), m_arm_isa); | 
|  | 13386 |  | 
|  | 13387 | if (opcode_data == NULL) | 
| Caroline Tice | 080bf61 | 2011-04-05 18:46:00 +0000 | [diff] [blame] | 13388 | return false; | 
| Caroline Tice | 080bf61 | 2011-04-05 18:46:00 +0000 | [diff] [blame] | 13389 |  | 
| Greg Clayton | 888a733 | 2011-04-26 04:39:08 +0000 | [diff] [blame] | 13390 | const bool auto_advance_pc = evaluate_options & eEmulateInstructionOptionAutoAdvancePC; | 
|  | 13391 | m_ignore_conditions = evaluate_options & eEmulateInstructionOptionIgnoreConditions; | 
| Caroline Tice | 0fe5a53 | 2011-04-08 23:33:06 +0000 | [diff] [blame] | 13392 |  | 
| Greg Clayton | 888a733 | 2011-04-26 04:39:08 +0000 | [diff] [blame] | 13393 | bool success = false; | 
|  | 13394 | if (m_opcode_cpsr == 0 || m_ignore_conditions == false) | 
| Caroline Tice | 0fe5a53 | 2011-04-08 23:33:06 +0000 | [diff] [blame] | 13395 | { | 
| Greg Clayton | 888a733 | 2011-04-26 04:39:08 +0000 | [diff] [blame] | 13396 | m_opcode_cpsr = ReadRegisterUnsigned (eRegisterKindDWARF, | 
| Greg Clayton | 061b79d | 2011-05-09 20:18:18 +0000 | [diff] [blame] | 13397 | dwarf_cpsr, | 
|  | 13398 | 0, | 
|  | 13399 | &success); | 
| Caroline Tice | 0fe5a53 | 2011-04-08 23:33:06 +0000 | [diff] [blame] | 13400 | } | 
|  | 13401 |  | 
| Greg Clayton | 888a733 | 2011-04-26 04:39:08 +0000 | [diff] [blame] | 13402 | // Only return false if we are unable to read the CPSR if we care about conditions | 
|  | 13403 | if (success == false && m_ignore_conditions == false) | 
|  | 13404 | return false; | 
|  | 13405 |  | 
|  | 13406 | uint32_t orig_pc_value = 0; | 
|  | 13407 | if (auto_advance_pc) | 
|  | 13408 | { | 
|  | 13409 | orig_pc_value = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc, 0, &success); | 
|  | 13410 | if (!success) | 
|  | 13411 | return false; | 
|  | 13412 | } | 
|  | 13413 |  | 
|  | 13414 | // Call the Emulate... function. | 
|  | 13415 | success = (this->*opcode_data->callback) (m_opcode.GetOpcode32(), opcode_data->encoding); | 
|  | 13416 | if (!success) | 
|  | 13417 | return false; | 
|  | 13418 |  | 
|  | 13419 | if (auto_advance_pc) | 
|  | 13420 | { | 
|  | 13421 | uint32_t after_pc_value = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc, 0, &success); | 
|  | 13422 | if (!success) | 
|  | 13423 | return false; | 
|  | 13424 |  | 
|  | 13425 | if (auto_advance_pc && (after_pc_value == orig_pc_value)) | 
|  | 13426 | { | 
|  | 13427 | if (opcode_data->size == eSize32) | 
|  | 13428 | after_pc_value += 4; | 
|  | 13429 | else if (opcode_data->size == eSize16) | 
|  | 13430 | after_pc_value += 2; | 
|  | 13431 |  | 
|  | 13432 | EmulateInstruction::Context context; | 
|  | 13433 | context.type = eContextAdvancePC; | 
|  | 13434 | context.SetNoArgs(); | 
|  | 13435 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc, after_pc_value)) | 
|  | 13436 | return false; | 
|  | 13437 |  | 
|  | 13438 | } | 
|  | 13439 | } | 
| Caroline Tice | 0fe5a53 | 2011-04-08 23:33:06 +0000 | [diff] [blame] | 13440 | return true; | 
| Greg Clayton | 64c8443 | 2011-01-21 22:02:52 +0000 | [diff] [blame] | 13441 | } | 
| Caroline Tice | 6b8d3b5 | 2011-04-19 23:30:03 +0000 | [diff] [blame] | 13442 |  | 
|  | 13443 | bool | 
| Caroline Tice | dfb2e20 | 2011-04-22 05:08:45 +0000 | [diff] [blame] | 13444 | EmulateInstructionARM::TestEmulation (Stream *out_stream, ArchSpec &arch, OptionValueDictionary *test_data) | 
| Caroline Tice | 6b8d3b5 | 2011-04-19 23:30:03 +0000 | [diff] [blame] | 13445 | { | 
| Caroline Tice | dfb2e20 | 2011-04-22 05:08:45 +0000 | [diff] [blame] | 13446 | if (!test_data) | 
| Caroline Tice | 6b8d3b5 | 2011-04-19 23:30:03 +0000 | [diff] [blame] | 13447 | { | 
| Caroline Tice | dfb2e20 | 2011-04-22 05:08:45 +0000 | [diff] [blame] | 13448 | out_stream->Printf ("TestEmulation: Missing test data.\n"); | 
| Caroline Tice | 6b8d3b5 | 2011-04-19 23:30:03 +0000 | [diff] [blame] | 13449 | return false; | 
|  | 13450 | } | 
| Caroline Tice | dfb2e20 | 2011-04-22 05:08:45 +0000 | [diff] [blame] | 13451 |  | 
|  | 13452 | static ConstString opcode_key ("opcode"); | 
|  | 13453 | static ConstString before_key ("before_state"); | 
|  | 13454 | static ConstString after_key ("after_state"); | 
|  | 13455 |  | 
|  | 13456 | OptionValueSP value_sp = test_data->GetValueForKey (opcode_key); | 
| Caroline Tice | 6b8d3b5 | 2011-04-19 23:30:03 +0000 | [diff] [blame] | 13457 |  | 
|  | 13458 | uint32_t test_opcode; | 
| Caroline Tice | dfb2e20 | 2011-04-22 05:08:45 +0000 | [diff] [blame] | 13459 | if ((value_sp.get() == NULL) || (value_sp->GetType() != OptionValue::eTypeUInt64)) | 
| Caroline Tice | 6b8d3b5 | 2011-04-19 23:30:03 +0000 | [diff] [blame] | 13460 | { | 
| Caroline Tice | dfb2e20 | 2011-04-22 05:08:45 +0000 | [diff] [blame] | 13461 | out_stream->Printf ("TestEmulation: Error reading opcode from test file.\n"); | 
| Caroline Tice | 6b8d3b5 | 2011-04-19 23:30:03 +0000 | [diff] [blame] | 13462 | return false; | 
|  | 13463 | } | 
| Caroline Tice | dfb2e20 | 2011-04-22 05:08:45 +0000 | [diff] [blame] | 13464 | test_opcode = value_sp->GetUInt64Value (); | 
| Caroline Tice | 6b8d3b5 | 2011-04-19 23:30:03 +0000 | [diff] [blame] | 13465 |  | 
| Caroline Tice | 6b8d3b5 | 2011-04-19 23:30:03 +0000 | [diff] [blame] | 13466 | if (arch.GetTriple().getArch() == llvm::Triple::arm) | 
|  | 13467 | { | 
|  | 13468 | m_opcode_mode = eModeARM; | 
|  | 13469 | m_opcode.SetOpcode32 (test_opcode); | 
|  | 13470 | } | 
|  | 13471 | else if (arch.GetTriple().getArch() == llvm::Triple::thumb) | 
|  | 13472 | { | 
|  | 13473 | m_opcode_mode = eModeThumb; | 
|  | 13474 | if (test_opcode < 0x10000) | 
|  | 13475 | m_opcode.SetOpcode16 (test_opcode); | 
|  | 13476 | else | 
|  | 13477 | m_opcode.SetOpcode32 (test_opcode); | 
|  | 13478 |  | 
|  | 13479 | } | 
|  | 13480 | else | 
|  | 13481 | { | 
| Caroline Tice | dfb2e20 | 2011-04-22 05:08:45 +0000 | [diff] [blame] | 13482 | out_stream->Printf ("TestEmulation:  Invalid arch.\n"); | 
| Caroline Tice | 6b8d3b5 | 2011-04-19 23:30:03 +0000 | [diff] [blame] | 13483 | return false; | 
|  | 13484 | } | 
|  | 13485 |  | 
| Caroline Tice | 6b8d3b5 | 2011-04-19 23:30:03 +0000 | [diff] [blame] | 13486 | EmulationStateARM before_state; | 
|  | 13487 | EmulationStateARM after_state; | 
|  | 13488 |  | 
| Caroline Tice | dfb2e20 | 2011-04-22 05:08:45 +0000 | [diff] [blame] | 13489 | value_sp = test_data->GetValueForKey (before_key); | 
|  | 13490 | if ((value_sp.get() == NULL) || (value_sp->GetType() != OptionValue::eTypeDictionary)) | 
| Caroline Tice | 6b8d3b5 | 2011-04-19 23:30:03 +0000 | [diff] [blame] | 13491 | { | 
| Caroline Tice | dfb2e20 | 2011-04-22 05:08:45 +0000 | [diff] [blame] | 13492 | out_stream->Printf ("TestEmulation:  Failed to find 'before' state.\n"); | 
| Caroline Tice | 6b8d3b5 | 2011-04-19 23:30:03 +0000 | [diff] [blame] | 13493 | return false; | 
|  | 13494 | } | 
| Caroline Tice | dfb2e20 | 2011-04-22 05:08:45 +0000 | [diff] [blame] | 13495 |  | 
| Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 13496 | OptionValueDictionary *state_dictionary = value_sp->GetAsDictionary (); | 
| Caroline Tice | dfb2e20 | 2011-04-22 05:08:45 +0000 | [diff] [blame] | 13497 | if (!before_state.LoadStateFromDictionary (state_dictionary)) | 
| Caroline Tice | 6b8d3b5 | 2011-04-19 23:30:03 +0000 | [diff] [blame] | 13498 | { | 
| Caroline Tice | dfb2e20 | 2011-04-22 05:08:45 +0000 | [diff] [blame] | 13499 | out_stream->Printf ("TestEmulation:  Failed loading 'before' state.\n"); | 
| Caroline Tice | 6b8d3b5 | 2011-04-19 23:30:03 +0000 | [diff] [blame] | 13500 | return false; | 
|  | 13501 | } | 
|  | 13502 |  | 
| Caroline Tice | dfb2e20 | 2011-04-22 05:08:45 +0000 | [diff] [blame] | 13503 | value_sp = test_data->GetValueForKey (after_key); | 
|  | 13504 | if ((value_sp.get() == NULL) || (value_sp->GetType() != OptionValue::eTypeDictionary)) | 
| Caroline Tice | 6b8d3b5 | 2011-04-19 23:30:03 +0000 | [diff] [blame] | 13505 | { | 
| Caroline Tice | dfb2e20 | 2011-04-22 05:08:45 +0000 | [diff] [blame] | 13506 | out_stream->Printf ("TestEmulation:  Failed to find 'after' state.\n"); | 
| Caroline Tice | 6b8d3b5 | 2011-04-19 23:30:03 +0000 | [diff] [blame] | 13507 | return false; | 
|  | 13508 | } | 
| Caroline Tice | dfb2e20 | 2011-04-22 05:08:45 +0000 | [diff] [blame] | 13509 |  | 
| Greg Clayton | 57b3c6b | 2011-04-27 22:04:39 +0000 | [diff] [blame] | 13510 | state_dictionary = value_sp->GetAsDictionary (); | 
| Caroline Tice | dfb2e20 | 2011-04-22 05:08:45 +0000 | [diff] [blame] | 13511 | if (!after_state.LoadStateFromDictionary (state_dictionary)) | 
|  | 13512 | { | 
|  | 13513 | out_stream->Printf ("TestEmulation: Failed loading 'after' state.\n"); | 
|  | 13514 | return false; | 
|  | 13515 | } | 
|  | 13516 |  | 
| Caroline Tice | 6b8d3b5 | 2011-04-19 23:30:03 +0000 | [diff] [blame] | 13517 | SetBaton ((void *) &before_state); | 
|  | 13518 | SetCallbacks (&EmulationStateARM::ReadPseudoMemory, | 
|  | 13519 | &EmulationStateARM::WritePseudoMemory, | 
|  | 13520 | &EmulationStateARM::ReadPseudoRegister, | 
|  | 13521 | &EmulationStateARM::WritePseudoRegister); | 
|  | 13522 |  | 
| Greg Clayton | 888a733 | 2011-04-26 04:39:08 +0000 | [diff] [blame] | 13523 | bool success = EvaluateInstruction (eEmulateInstructionOptionAutoAdvancePC); | 
| Caroline Tice | 6b8d3b5 | 2011-04-19 23:30:03 +0000 | [diff] [blame] | 13524 | if (!success) | 
|  | 13525 | { | 
| Caroline Tice | dfb2e20 | 2011-04-22 05:08:45 +0000 | [diff] [blame] | 13526 | out_stream->Printf ("TestEmulation:  EvaluateInstruction() failed.\n"); | 
| Caroline Tice | 6b8d3b5 | 2011-04-19 23:30:03 +0000 | [diff] [blame] | 13527 | return false; | 
|  | 13528 | } | 
|  | 13529 |  | 
|  | 13530 | success = before_state.CompareState (after_state); | 
| Caroline Tice | dfb2e20 | 2011-04-22 05:08:45 +0000 | [diff] [blame] | 13531 | if (!success) | 
|  | 13532 | out_stream->Printf ("TestEmulation:  'before' and 'after' states do not match.\n"); | 
|  | 13533 |  | 
| Caroline Tice | 6b8d3b5 | 2011-04-19 23:30:03 +0000 | [diff] [blame] | 13534 | return success; | 
|  | 13535 | } | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 13536 | // | 
|  | 13537 | // | 
|  | 13538 | //const char * | 
|  | 13539 | //EmulateInstructionARM::GetRegisterName (uint32_t reg_kind, uint32_t reg_num) | 
|  | 13540 | //{ | 
|  | 13541 | //    if (reg_kind == eRegisterKindGeneric) | 
|  | 13542 | //    { | 
|  | 13543 | //        switch (reg_num) | 
|  | 13544 | //        { | 
|  | 13545 | //        case LLDB_REGNUM_GENERIC_PC:    return "pc"; | 
|  | 13546 | //        case LLDB_REGNUM_GENERIC_SP:    return "sp"; | 
|  | 13547 | //        case LLDB_REGNUM_GENERIC_FP:    return "fp"; | 
|  | 13548 | //        case LLDB_REGNUM_GENERIC_RA:    return "lr"; | 
|  | 13549 | //        case LLDB_REGNUM_GENERIC_FLAGS: return "cpsr"; | 
|  | 13550 | //        default: return NULL; | 
|  | 13551 | //        } | 
|  | 13552 | //    } | 
|  | 13553 | //    else if (reg_kind == eRegisterKindDWARF) | 
|  | 13554 | //    { | 
|  | 13555 | //        return GetARMDWARFRegisterName (reg_num); | 
|  | 13556 | //    } | 
|  | 13557 | //    return NULL; | 
|  | 13558 | //} | 
|  | 13559 | // | 
|  | 13560 | bool | 
|  | 13561 | EmulateInstructionARM::CreateFunctionEntryUnwind (UnwindPlan &unwind_plan) | 
| Greg Clayton | 888a733 | 2011-04-26 04:39:08 +0000 | [diff] [blame] | 13562 | { | 
| Greg Clayton | 75906e4 | 2011-05-11 18:39:18 +0000 | [diff] [blame] | 13563 | unwind_plan.Clear(); | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 13564 | unwind_plan.SetRegisterKind (eRegisterKindDWARF); | 
|  | 13565 |  | 
|  | 13566 | UnwindPlan::Row row; | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 13567 |  | 
|  | 13568 | // Our previous Call Frame Address is the stack pointer | 
|  | 13569 | row.SetCFARegister (dwarf_sp); | 
|  | 13570 |  | 
|  | 13571 | // Our previous PC is in the LR | 
| Greg Clayton | 75906e4 | 2011-05-11 18:39:18 +0000 | [diff] [blame] | 13572 | row.SetRegisterLocationToRegister(dwarf_pc, dwarf_lr, true); | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 13573 | unwind_plan.AppendRow (row); | 
|  | 13574 |  | 
|  | 13575 | // All other registers are the same. | 
|  | 13576 |  | 
|  | 13577 | unwind_plan.SetSourceName ("EmulateInstructionARM"); | 
|  | 13578 | return true; | 
| Greg Clayton | 888a733 | 2011-04-26 04:39:08 +0000 | [diff] [blame] | 13579 | } | 
|  | 13580 |  | 
| Greg Clayton | c07d451 | 2011-04-26 23:48:45 +0000 | [diff] [blame] | 13581 |  | 
|  | 13582 |  | 
|  | 13583 |  |