1 /* Copyright (c) 2013-2014 Jeffrey Pfau 2 * 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 #include <mgba/internal/arm/isa-thumb.h> 7 8 #include <mgba/internal/arm/isa-inlines.h> 9 #include <mgba/internal/arm/emitter-thumb.h> 10 11 // Instruction definitions 12 // Beware pre-processor insanity 13 14 #define THUMB_ADDITION_S(M, N, D) \ 15 cpu->cpsr.flags = 0; \ 16 cpu->cpsr.n = ARM_SIGN(D); \ 17 cpu->cpsr.z = !(D); \ 18 cpu->cpsr.c = ARM_CARRY_FROM(M, N, D); \ 19 cpu->cpsr.v = ARM_V_ADDITION(M, N, D); 20 21 #define THUMB_SUBTRACTION_S(M, N, D) \ 22 cpu->cpsr.flags = 0; \ 23 cpu->cpsr.n = ARM_SIGN(D); \ 24 cpu->cpsr.z = !(D); \ 25 cpu->cpsr.c = ARM_BORROW_FROM(M, N, D); \ 26 cpu->cpsr.v = ARM_V_SUBTRACTION(M, N, D); 27 28 #define THUMB_SUBTRACTION_CARRY_S(M, N, D, C) \ 29 cpu->cpsr.n = ARM_SIGN(D); \ 30 cpu->cpsr.z = !(D); \ 31 cpu->cpsr.c = ARM_BORROW_FROM_CARRY(M, N, D, C); \ 32 cpu->cpsr.v = ARM_V_SUBTRACTION(M, N, D); 33 34 #define THUMB_NEUTRAL_S(M, N, D) \ 35 cpu->cpsr.n = ARM_SIGN(D); \ 36 cpu->cpsr.z = !(D); 37 38 #define THUMB_ADDITION(D, M, N) \ 39 int n = N; \ 40 int m = M; \ 41 D = M + N; \ 42 THUMB_ADDITION_S(m, n, D) 43 44 #define THUMB_SUBTRACTION(D, M, N) \ 45 int n = N; \ 46 int m = M; \ 47 D = M - N; \ 48 THUMB_SUBTRACTION_S(m, n, D) 49 50 #define THUMB_PREFETCH_CYCLES (1 + cpu->memory.activeSeqCycles16) 51 52 #define THUMB_LOAD_POST_BODY \ 53 currentCycles += cpu->memory.activeNonseqCycles16 - cpu->memory.activeSeqCycles16; 54 55 #define THUMB_STORE_POST_BODY \ 56 currentCycles += cpu->memory.activeNonseqCycles16 - cpu->memory.activeSeqCycles16; 57 58 #define DEFINE_INSTRUCTION_THUMB(NAME, BODY) \ 59 static void _ThumbInstruction ## NAME (struct ARMCore* cpu, unsigned opcode) { \ 60 int currentCycles = THUMB_PREFETCH_CYCLES; \ 61 BODY; \ 62 cpu->cycles += currentCycles; \ 63 } 64 65 #define DEFINE_IMMEDIATE_5_INSTRUCTION_THUMB(NAME, BODY) \ 66 DEFINE_INSTRUCTION_THUMB(NAME, \ 67 int immediate = (opcode >> 6) & 0x001F; \ 68 int rd = opcode & 0x0007; \ 69 int rm = (opcode >> 3) & 0x0007; \ 70 BODY;) 71 72 DEFINE_IMMEDIATE_5_INSTRUCTION_THUMB(LSL1, 73 if (!immediate) { 74 cpu->gprs[rd] = cpu->gprs[rm]; 75 } else { 76 cpu->cpsr.c = (cpu->gprs[rm] >> (32 - immediate)) & 1; 77 cpu->gprs[rd] = cpu->gprs[rm] << immediate; 78 } 79 THUMB_NEUTRAL_S( , , cpu->gprs[rd]);) 80 81 DEFINE_IMMEDIATE_5_INSTRUCTION_THUMB(LSR1, 82 if (!immediate) { 83 cpu->cpsr.c = ARM_SIGN(cpu->gprs[rm]); 84 cpu->gprs[rd] = 0; 85 } else { 86 cpu->cpsr.c = (cpu->gprs[rm] >> (immediate - 1)) & 1; 87 cpu->gprs[rd] = ((uint32_t) cpu->gprs[rm]) >> immediate; 88 } 89 THUMB_NEUTRAL_S( , , cpu->gprs[rd]);) 90 91 DEFINE_IMMEDIATE_5_INSTRUCTION_THUMB(ASR1, 92 if (!immediate) { 93 cpu->cpsr.c = ARM_SIGN(cpu->gprs[rm]); 94 if (cpu->cpsr.c) { 95 cpu->gprs[rd] = 0xFFFFFFFF; 96 } else { 97 cpu->gprs[rd] = 0; 98 } 99 } else { 100 cpu->cpsr.c = (cpu->gprs[rm] >> (immediate - 1)) & 1; 101 cpu->gprs[rd] = cpu->gprs[rm] >> immediate; 102 } 103 THUMB_NEUTRAL_S( , , cpu->gprs[rd]);) 104 105 DEFINE_IMMEDIATE_5_INSTRUCTION_THUMB(LDR1, cpu->gprs[rd] = cpu->memory.load32(cpu, cpu->gprs[rm] + immediate * 4, ¤tCycles); THUMB_LOAD_POST_BODY;) 106 DEFINE_IMMEDIATE_5_INSTRUCTION_THUMB(LDRB1, cpu->gprs[rd] = cpu->memory.load8(cpu, cpu->gprs[rm] + immediate, ¤tCycles); THUMB_LOAD_POST_BODY;) 107 DEFINE_IMMEDIATE_5_INSTRUCTION_THUMB(LDRH1, cpu->gprs[rd] = cpu->memory.load16(cpu, cpu->gprs[rm] + immediate * 2, ¤tCycles); THUMB_LOAD_POST_BODY;) 108 DEFINE_IMMEDIATE_5_INSTRUCTION_THUMB(STR1, cpu->memory.store32(cpu, cpu->gprs[rm] + immediate * 4, cpu->gprs[rd], ¤tCycles); THUMB_STORE_POST_BODY;) 109 DEFINE_IMMEDIATE_5_INSTRUCTION_THUMB(STRB1, cpu->memory.store8(cpu, cpu->gprs[rm] + immediate, cpu->gprs[rd], ¤tCycles); THUMB_STORE_POST_BODY;) 110 DEFINE_IMMEDIATE_5_INSTRUCTION_THUMB(STRH1, cpu->memory.store16(cpu, cpu->gprs[rm] + immediate * 2, cpu->gprs[rd], ¤tCycles); THUMB_STORE_POST_BODY;) 111 112 #define DEFINE_DATA_FORM_1_INSTRUCTION_THUMB(NAME, BODY) \ 113 DEFINE_INSTRUCTION_THUMB(NAME, \ 114 int rm = (opcode >> 6) & 0x0007; \ 115 int rd = opcode & 0x0007; \ 116 int rn = (opcode >> 3) & 0x0007; \ 117 BODY;) 118 119 DEFINE_DATA_FORM_1_INSTRUCTION_THUMB(ADD3, THUMB_ADDITION(cpu->gprs[rd], cpu->gprs[rn], cpu->gprs[rm])) 120 DEFINE_DATA_FORM_1_INSTRUCTION_THUMB(SUB3, THUMB_SUBTRACTION(cpu->gprs[rd], cpu->gprs[rn], cpu->gprs[rm])) 121 122 #define DEFINE_DATA_FORM_2_INSTRUCTION_THUMB(NAME, BODY) \ 123 DEFINE_INSTRUCTION_THUMB(NAME, \ 124 int immediate = (opcode >> 6) & 0x0007; \ 125 int rd = opcode & 0x0007; \ 126 int rn = (opcode >> 3) & 0x0007; \ 127 BODY;) 128 129 DEFINE_DATA_FORM_2_INSTRUCTION_THUMB(ADD1, THUMB_ADDITION(cpu->gprs[rd], cpu->gprs[rn], immediate)) 130 DEFINE_DATA_FORM_2_INSTRUCTION_THUMB(SUB1, THUMB_SUBTRACTION(cpu->gprs[rd], cpu->gprs[rn], immediate)) 131 132 #define DEFINE_DATA_FORM_3_INSTRUCTION_THUMB(NAME, BODY) \ 133 DEFINE_INSTRUCTION_THUMB(NAME, \ 134 int rd = (opcode >> 8) & 0x0007; \ 135 int immediate = opcode & 0x00FF; \ 136 BODY;) 137 138 DEFINE_DATA_FORM_3_INSTRUCTION_THUMB(ADD2, THUMB_ADDITION(cpu->gprs[rd], cpu->gprs[rd], immediate)) 139 DEFINE_DATA_FORM_3_INSTRUCTION_THUMB(CMP1, int aluOut = cpu->gprs[rd] - immediate; THUMB_SUBTRACTION_S(cpu->gprs[rd], immediate, aluOut)) 140 DEFINE_DATA_FORM_3_INSTRUCTION_THUMB(MOV1, cpu->gprs[rd] = immediate; THUMB_NEUTRAL_S(, , cpu->gprs[rd])) 141 DEFINE_DATA_FORM_3_INSTRUCTION_THUMB(SUB2, THUMB_SUBTRACTION(cpu->gprs[rd], cpu->gprs[rd], immediate)) 142 143 #define DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(NAME, BODY) \ 144 DEFINE_INSTRUCTION_THUMB(NAME, \ 145 int rd = opcode & 0x0007; \ 146 int rn = (opcode >> 3) & 0x0007; \ 147 BODY;) 148 149 DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(AND, cpu->gprs[rd] = cpu->gprs[rd] & cpu->gprs[rn]; THUMB_NEUTRAL_S( , , cpu->gprs[rd])) 150 DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(EOR, cpu->gprs[rd] = cpu->gprs[rd] ^ cpu->gprs[rn]; THUMB_NEUTRAL_S( , , cpu->gprs[rd])) 151 DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(LSL2, 152 int rs = cpu->gprs[rn] & 0xFF; 153 if (rs) { 154 if (rs < 32) { 155 cpu->cpsr.c = (cpu->gprs[rd] >> (32 - rs)) & 1; 156 cpu->gprs[rd] <<= rs; 157 } else { 158 if (rs > 32) { 159 cpu->cpsr.c = 0; 160 } else { 161 cpu->cpsr.c = cpu->gprs[rd] & 0x00000001; 162 } 163 cpu->gprs[rd] = 0; 164 } 165 } 166 ++currentCycles; 167 THUMB_NEUTRAL_S( , , cpu->gprs[rd])) 168 169 DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(LSR2, 170 int rs = cpu->gprs[rn] & 0xFF; 171 if (rs) { 172 if (rs < 32) { 173 cpu->cpsr.c = (cpu->gprs[rd] >> (rs - 1)) & 1; 174 cpu->gprs[rd] = (uint32_t) cpu->gprs[rd] >> rs; 175 } else { 176 if (rs > 32) { 177 cpu->cpsr.c = 0; 178 } else { 179 cpu->cpsr.c = ARM_SIGN(cpu->gprs[rd]); 180 } 181 cpu->gprs[rd] = 0; 182 } 183 } 184 ++currentCycles; 185 THUMB_NEUTRAL_S( , , cpu->gprs[rd])) 186 187 DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(ASR2, 188 int rs = cpu->gprs[rn] & 0xFF; 189 if (rs) { 190 if (rs < 32) { 191 cpu->cpsr.c = (cpu->gprs[rd] >> (rs - 1)) & 1; 192 cpu->gprs[rd] >>= rs; 193 } else { 194 cpu->cpsr.c = ARM_SIGN(cpu->gprs[rd]); 195 if (cpu->cpsr.c) { 196 cpu->gprs[rd] = 0xFFFFFFFF; 197 } else { 198 cpu->gprs[rd] = 0; 199 } 200 } 201 } 202 ++currentCycles; 203 THUMB_NEUTRAL_S( , , cpu->gprs[rd])) 204 205 DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(ADC, 206 int n = cpu->gprs[rn]; 207 int d = cpu->gprs[rd]; 208 cpu->gprs[rd] = d + n + cpu->cpsr.c; 209 THUMB_ADDITION_S(d, n, cpu->gprs[rd]);) 210 211 DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(SBC, 212 int n = cpu->gprs[rn]; 213 int d = cpu->gprs[rd]; 214 cpu->gprs[rd] = d - n - !cpu->cpsr.c; 215 THUMB_SUBTRACTION_CARRY_S(d, n, cpu->gprs[rd], !cpu->cpsr.c);) 216 217 DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(ROR, 218 int rs = cpu->gprs[rn] & 0xFF; 219 if (rs) { 220 int r4 = rs & 0x1F; 221 if (r4 > 0) { 222 cpu->cpsr.c = (cpu->gprs[rd] >> (r4 - 1)) & 1; 223 cpu->gprs[rd] = ROR(cpu->gprs[rd], r4); 224 } else { 225 cpu->cpsr.c = ARM_SIGN(cpu->gprs[rd]); 226 } 227 } 228 ++currentCycles; 229 THUMB_NEUTRAL_S( , , cpu->gprs[rd]);) 230 DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(TST, int32_t aluOut = cpu->gprs[rd] & cpu->gprs[rn]; THUMB_NEUTRAL_S(cpu->gprs[rd], cpu->gprs[rn], aluOut)) 231 DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(NEG, THUMB_SUBTRACTION(cpu->gprs[rd], 0, cpu->gprs[rn])) 232 DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(CMP2, int32_t aluOut = cpu->gprs[rd] - cpu->gprs[rn]; THUMB_SUBTRACTION_S(cpu->gprs[rd], cpu->gprs[rn], aluOut)) 233 DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(CMN, int32_t aluOut = cpu->gprs[rd] + cpu->gprs[rn]; THUMB_ADDITION_S(cpu->gprs[rd], cpu->gprs[rn], aluOut)) 234 DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(ORR, cpu->gprs[rd] = cpu->gprs[rd] | cpu->gprs[rn]; THUMB_NEUTRAL_S( , , cpu->gprs[rd])) 235 DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(MUL, ARM_WAIT_MUL(cpu->gprs[rd], 0); cpu->gprs[rd] *= cpu->gprs[rn]; THUMB_NEUTRAL_S( , , cpu->gprs[rd]); currentCycles += cpu->memory.activeNonseqCycles16 - cpu->memory.activeSeqCycles16) 236 DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(BIC, cpu->gprs[rd] = cpu->gprs[rd] & ~cpu->gprs[rn]; THUMB_NEUTRAL_S( , , cpu->gprs[rd])) 237 DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(MVN, cpu->gprs[rd] = ~cpu->gprs[rn]; THUMB_NEUTRAL_S( , , cpu->gprs[rd])) 238 239 #define DEFINE_INSTRUCTION_WITH_HIGH_EX_THUMB(NAME, H1, H2, BODY) \ 240 DEFINE_INSTRUCTION_THUMB(NAME, \ 241 int rd = (opcode & 0x0007) | H1; \ 242 int rm = ((opcode >> 3) & 0x0007) | H2; \ 243 BODY;) 244 245 #define DEFINE_INSTRUCTION_WITH_HIGH_THUMB(NAME, BODY) \ 246 DEFINE_INSTRUCTION_WITH_HIGH_EX_THUMB(NAME ## 00, 0, 0, BODY) \ 247 DEFINE_INSTRUCTION_WITH_HIGH_EX_THUMB(NAME ## 01, 0, 8, BODY) \ 248 DEFINE_INSTRUCTION_WITH_HIGH_EX_THUMB(NAME ## 10, 8, 0, BODY) \ 249 DEFINE_INSTRUCTION_WITH_HIGH_EX_THUMB(NAME ## 11, 8, 8, BODY) 250 251 DEFINE_INSTRUCTION_WITH_HIGH_THUMB(ADD4, 252 cpu->gprs[rd] += cpu->gprs[rm]; 253 if (rd == ARM_PC) { 254 currentCycles += ThumbWritePC(cpu); 255 }) 256 257 DEFINE_INSTRUCTION_WITH_HIGH_THUMB(CMP3, int32_t aluOut = cpu->gprs[rd] - cpu->gprs[rm]; THUMB_SUBTRACTION_S(cpu->gprs[rd], cpu->gprs[rm], aluOut)) 258 DEFINE_INSTRUCTION_WITH_HIGH_THUMB(MOV3, 259 cpu->gprs[rd] = cpu->gprs[rm]; 260 if (rd == ARM_PC) { 261 currentCycles += ThumbWritePC(cpu); 262 }) 263 264 #define DEFINE_IMMEDIATE_WITH_REGISTER_THUMB(NAME, BODY) \ 265 DEFINE_INSTRUCTION_THUMB(NAME, \ 266 int rd = (opcode >> 8) & 0x0007; \ 267 int immediate = (opcode & 0x00FF) << 2; \ 268 BODY;) 269 270 DEFINE_IMMEDIATE_WITH_REGISTER_THUMB(LDR3, cpu->gprs[rd] = cpu->memory.load32(cpu, (cpu->gprs[ARM_PC] & 0xFFFFFFFC) + immediate, ¤tCycles); THUMB_LOAD_POST_BODY;) 271 DEFINE_IMMEDIATE_WITH_REGISTER_THUMB(LDR4, cpu->gprs[rd] = cpu->memory.load32(cpu, cpu->gprs[ARM_SP] + immediate, ¤tCycles); THUMB_LOAD_POST_BODY;) 272 DEFINE_IMMEDIATE_WITH_REGISTER_THUMB(STR3, cpu->memory.store32(cpu, cpu->gprs[ARM_SP] + immediate, cpu->gprs[rd], ¤tCycles); THUMB_STORE_POST_BODY;) 273 274 DEFINE_IMMEDIATE_WITH_REGISTER_THUMB(ADD5, cpu->gprs[rd] = (cpu->gprs[ARM_PC] & 0xFFFFFFFC) + immediate) 275 DEFINE_IMMEDIATE_WITH_REGISTER_THUMB(ADD6, cpu->gprs[rd] = cpu->gprs[ARM_SP] + immediate) 276 277 #define DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(NAME, BODY) \ 278 DEFINE_INSTRUCTION_THUMB(NAME, \ 279 int rm = (opcode >> 6) & 0x0007; \ 280 int rd = opcode & 0x0007; \ 281 int rn = (opcode >> 3) & 0x0007; \ 282 BODY;) 283 284 DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDR2, cpu->gprs[rd] = cpu->memory.load32(cpu, cpu->gprs[rn] + cpu->gprs[rm], ¤tCycles); THUMB_LOAD_POST_BODY;) 285 DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDRB2, cpu->gprs[rd] = cpu->memory.load8(cpu, cpu->gprs[rn] + cpu->gprs[rm], ¤tCycles); THUMB_LOAD_POST_BODY;) 286 DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDRH2, cpu->gprs[rd] = cpu->memory.load16(cpu, cpu->gprs[rn] + cpu->gprs[rm], ¤tCycles); THUMB_LOAD_POST_BODY;) 287 DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDRSB, cpu->gprs[rd] = ARM_SXT_8(cpu->memory.load8(cpu, cpu->gprs[rn] + cpu->gprs[rm], ¤tCycles)); THUMB_LOAD_POST_BODY;) 288 DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDRSH, rm = cpu->gprs[rn] + cpu->gprs[rm]; cpu->gprs[rd] = rm & 1 ? ARM_SXT_8(cpu->memory.load16(cpu, rm, ¤tCycles)) : ARM_SXT_16(cpu->memory.load16(cpu, rm, ¤tCycles)); THUMB_LOAD_POST_BODY;) 289 DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(STR2, cpu->memory.store32(cpu, cpu->gprs[rn] + cpu->gprs[rm], cpu->gprs[rd], ¤tCycles); THUMB_STORE_POST_BODY;) 290 DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(STRB2, cpu->memory.store8(cpu, cpu->gprs[rn] + cpu->gprs[rm], cpu->gprs[rd], ¤tCycles); THUMB_STORE_POST_BODY;) 291 DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(STRH2, cpu->memory.store16(cpu, cpu->gprs[rn] + cpu->gprs[rm], cpu->gprs[rd], ¤tCycles); THUMB_STORE_POST_BODY;) 292 293 #define DEFINE_LOAD_STORE_MULTIPLE_THUMB(NAME, RN, LS, DIRECTION, PRE_BODY, WRITEBACK) \ 294 DEFINE_INSTRUCTION_THUMB(NAME, \ 295 int rn = RN; \ 296 UNUSED(rn); \ 297 int rs = opcode & 0xFF; \ 298 int32_t address = cpu->gprs[RN]; \ 299 PRE_BODY; \ 300 address = cpu->memory. LS ## Multiple(cpu, address, rs, LSM_ ## DIRECTION, ¤tCycles); \ 301 WRITEBACK;) 302 303 DEFINE_LOAD_STORE_MULTIPLE_THUMB(LDMIA, 304 (opcode >> 8) & 0x0007, 305 load, 306 IA, 307 , 308 THUMB_LOAD_POST_BODY; 309 if (!rs) { 310 currentCycles += ThumbWritePC(cpu); 311 } 312 if (!((1 << rn) & rs)) { 313 cpu->gprs[rn] = address; 314 }) 315 316 DEFINE_LOAD_STORE_MULTIPLE_THUMB(STMIA, 317 (opcode >> 8) & 0x0007, 318 store, 319 IA, 320 , 321 THUMB_STORE_POST_BODY; 322 cpu->gprs[rn] = address;) 323 324 #define DEFINE_CONDITIONAL_BRANCH_THUMB(COND) \ 325 DEFINE_INSTRUCTION_THUMB(B ## COND, \ 326 if (ARM_COND_ ## COND) { \ 327 int8_t immediate = opcode; \ 328 cpu->gprs[ARM_PC] += (int32_t) immediate << 1; \ 329 currentCycles += ThumbWritePC(cpu); \ 330 }) 331 332 DEFINE_CONDITIONAL_BRANCH_THUMB(EQ) 333 DEFINE_CONDITIONAL_BRANCH_THUMB(NE) 334 DEFINE_CONDITIONAL_BRANCH_THUMB(CS) 335 DEFINE_CONDITIONAL_BRANCH_THUMB(CC) 336 DEFINE_CONDITIONAL_BRANCH_THUMB(MI) 337 DEFINE_CONDITIONAL_BRANCH_THUMB(PL) 338 DEFINE_CONDITIONAL_BRANCH_THUMB(VS) 339 DEFINE_CONDITIONAL_BRANCH_THUMB(VC) 340 DEFINE_CONDITIONAL_BRANCH_THUMB(LS) 341 DEFINE_CONDITIONAL_BRANCH_THUMB(HI) 342 DEFINE_CONDITIONAL_BRANCH_THUMB(GE) 343 DEFINE_CONDITIONAL_BRANCH_THUMB(LT) 344 DEFINE_CONDITIONAL_BRANCH_THUMB(GT) 345 DEFINE_CONDITIONAL_BRANCH_THUMB(LE) 346 347 DEFINE_INSTRUCTION_THUMB(ADD7, cpu->gprs[ARM_SP] += (opcode & 0x7F) << 2) 348 DEFINE_INSTRUCTION_THUMB(SUB4, cpu->gprs[ARM_SP] -= (opcode & 0x7F) << 2) 349 350 DEFINE_LOAD_STORE_MULTIPLE_THUMB(POP, 351 ARM_SP, 352 load, 353 IA, 354 , 355 THUMB_LOAD_POST_BODY; 356 cpu->gprs[ARM_SP] = address) 357 358 DEFINE_LOAD_STORE_MULTIPLE_THUMB(POPR, 359 ARM_SP, 360 load, 361 IA, 362 rs |= 1 << ARM_PC, 363 THUMB_LOAD_POST_BODY; 364 cpu->gprs[ARM_SP] = address; 365 currentCycles += ThumbWritePC(cpu);) 366 367 DEFINE_LOAD_STORE_MULTIPLE_THUMB(PUSH, 368 ARM_SP, 369 store, 370 DB, 371 , 372 THUMB_STORE_POST_BODY; 373 cpu->gprs[ARM_SP] = address) 374 375 DEFINE_LOAD_STORE_MULTIPLE_THUMB(PUSHR, 376 ARM_SP, 377 store, 378 DB, 379 rs |= 1 << ARM_LR, 380 THUMB_STORE_POST_BODY; 381 cpu->gprs[ARM_SP] = address) 382 383 DEFINE_INSTRUCTION_THUMB(ILL, ARM_ILL) 384 DEFINE_INSTRUCTION_THUMB(BKPT, cpu->irqh.bkpt16(cpu, opcode & 0xFF);) 385 DEFINE_INSTRUCTION_THUMB(B, 386 int16_t immediate = (opcode & 0x07FF) << 5; 387 cpu->gprs[ARM_PC] += (((int32_t) immediate) >> 4); 388 currentCycles += ThumbWritePC(cpu);) 389 390 DEFINE_INSTRUCTION_THUMB(BL1, 391 int16_t immediate = (opcode & 0x07FF) << 5; 392 cpu->gprs[ARM_LR] = cpu->gprs[ARM_PC] + (((int32_t) immediate) << 7);) 393 394 DEFINE_INSTRUCTION_THUMB(BL2, 395 uint16_t immediate = (opcode & 0x07FF) << 1; 396 uint32_t pc = cpu->gprs[ARM_PC]; 397 cpu->gprs[ARM_PC] = cpu->gprs[ARM_LR] + immediate; 398 cpu->gprs[ARM_LR] = pc - 1; 399 currentCycles += ThumbWritePC(cpu);) 400 401 DEFINE_INSTRUCTION_THUMB(BX, 402 int rm = (opcode >> 3) & 0xF; 403 _ARMSetMode(cpu, cpu->gprs[rm] & 0x00000001); 404 int misalign = 0; 405 if (rm == ARM_PC) { 406 misalign = cpu->gprs[rm] & 0x00000002; 407 } 408 cpu->gprs[ARM_PC] = (cpu->gprs[rm] & 0xFFFFFFFE) - misalign; 409 if (cpu->executionMode == MODE_THUMB) { 410 currentCycles += ThumbWritePC(cpu); 411 } else { 412 currentCycles += ARMWritePC(cpu); 413 }) 414 415 DEFINE_INSTRUCTION_THUMB(SWI, cpu->irqh.swi16(cpu, opcode & 0xFF)) 416 417 const ThumbInstruction _thumbTable[0x400] = { 418 DECLARE_THUMB_EMITTER_BLOCK(_ThumbInstruction) 419 }; 420