1 module gbaid.gba.arm; 2 3 import core.bitop : popcnt; 4 5 import std..string : format; 6 7 import gbaid.util; 8 9 import gbaid.gba.instable; 10 11 private enum ARM_OPCODE_BIT_COUNT = 12; 12 private immutable Executor[1 << ARM_OPCODE_BIT_COUNT] ARM_EXECUTORS = createARMTable(); 13 14 public void executeARMInstruction(Registers* registers, MemoryBus* memory, int instruction) { 15 if (!registers.checkCondition(instruction >>> 28)) { 16 return; 17 } 18 int code = instruction.getBits(20, 27) << 4 | instruction.getBits(4, 7); 19 ARM_EXECUTORS[code](registers, memory, instruction); 20 } 21 22 private Executor[] createARMTable() { 23 /* 24 The instruction encoding, modified from: http://problemkaputt.de/gbatek.htm#arminstructionsummary 25 26 |..3 ..................2 ..................1 ..................0| 27 |1_0_9_8_7_6_5_4_3_2_1_0_9_8_7_6_5_4_3_2_1_0_9_8_7_6_5_4_3_2_1_0| 28 |_Cond__|0_0_0|___Op__|S|__Rn___|__Rd___|__Shift__|Typ|0|__Rm___| DataProc 29 |_Cond__|0_0_0|___Op__|S|__Rn___|__Rd___|__Rs___|0|Typ|1|__Rm___| DataProc 30 |_Cond__|0_0_1|___Op__|S|__Rn___|__Rd___|_Shift_|___Immediate___| DataProc 31 |_Cond__|0_0_1_1_0|P|1|0|_Field_|__Rd___|_Shift_|___Immediate___| PSR Imm 32 |_Cond__|0_0_0_1_0|P|L|0|_Field_|__Rd___|0_0_0_0|0_0_0_0|__Rm___| PSR Reg 33 |_Cond__|0_0_0_1_0_0_1_0_1_1_1_1_1_1_1_1_1_1_1_1|0_0|L|1|__Rn___| BX,BLX 34 |_Cond__|0_0_0_0_0_0|A|S|__Rd___|__Rn___|__Rs___|1_0_0_1|__Rm___| Multiply 35 |_Cond__|0_0_0_0_1|U|A|S|_RdHi__|_RdLo__|__Rs___|1_0_0_1|__Rm___| MulLong 36 |_Cond__|0_0_0_1_0|B|0_0|__Rn___|__Rd___|0_0_0_0|1_0_0_1|__Rm___| TransSwp12 37 |_Cond__|0_0_0|P|U|0|W|L|__Rn___|__Rd___|0_0_0_0|1|S|H|1|__Rm___| TransReg10 38 |_Cond__|0_0_0|P|U|1|W|L|__Rn___|__Rd___|OffsetH|1|S|H|1|OffsetL| TransImm10 39 |_Cond__|0_1_0|P|U|B|W|L|__Rn___|__Rd___|_________Offset________| TransImm9 40 |_Cond__|0_1_1|P|U|B|W|L|__Rn___|__Rd___|__Shift__|Typ|0|__Rm___| TransReg9 41 |_Cond__|1_0_0|P|U|S|W|L|__Rn___|__________Register_List________| BlockTrans 42 |_Cond__|1_0_1|L|___________________Offset______________________| B,BL,BLX 43 |_Cond__|1_1_1_1|_____________Ignored_by_Processor______________| SWI 44 45 The op code is the concatenation of bits 20 to 27 with bits 4 to 7 46 For some instructions some of these bits are not used, hence the need for don't cares 47 Anything not covered by the table must raise an UNDEFINED interrupt 48 */ 49 50 auto table = createTable!(unsupported)(12); 51 52 // Bits are OpCode(4),S(1) 53 // where S is set flags 54 addSubTable!("000tttttddd0", dataProcessing_RegShiftImm, unsupported)(table); 55 addSubTable!("000ttttt0dd1", dataProcessing_RegShiftReg, unsupported)(table); 56 addSubTable!("001tttttdddd", dataProcessing_Imm, unsupported)(table); 57 58 // Bits are P(1) 59 // where P is use SPSR 60 addSubTable!("00110t10dddd", psrTransfer_Imm, unsupported)(table); 61 62 // Bits are P(1),~L(1) 63 // where P is use SPSR and L is load 64 addSubTable!("00010tt00000", psrTransfer_Reg, unsupported)(table); 65 66 // No bits 67 addSubTable!("000100100001", branchAndExchange, unsupported)(table); 68 69 // Bits are A(1),S(1) 70 // where A is accumulate and S is set flags 71 addSubTable!("000000tt1001", multiply_Int, unsupported)(table); 72 73 // Bits are ~U(1),A(1),S(1) 74 // where U is unsigned, A is accumulate and S is set flags 75 addSubTable!("00001ttt1001", multiply_Long, unsupported)(table); 76 77 // Bits are B(1) 78 // where B is byte quantity 79 addSubTable!("00010t001001", singleDataSwap, unsupported)(table); 80 81 // Bits are P(1),U(1),W(1),L(1),S(1),H(1) 82 // where P is pre-increment, U is up-increment, W is write back and L is load, S is signed and H is halfword 83 addSubTable!("000tt0tt1tt1", halfwordAndSignedDataTransfer_Reg, unsupported)(table); 84 addSubTable!("000tt1tt1tt1", halfwordAndSignedDataTransfer_Imm, unsupported)(table); 85 86 // Bits are P(1),U(1),B(1),W(1),L(1) 87 // where P is pre-increment, U is up-increment, B is byte quantity, W is write back and L is load 88 addSubTable!("010tttttdddd", singleDataTransfer_Imm, unsupported)(table); 89 addSubTable!("011tttttddd0", singleDataTransfer_Reg, unsupported)(table); 90 91 // Bits are P(1),U(1),S(1),W(1),L(1) 92 // where P is pre-increment, U is up-increment, S is load PSR or force user, W is write back and L is load 93 addSubTable!("100tttttdddd", blockDataTransfer, unsupported)(table); 94 95 // Bits are L(1) 96 // where L is link 97 addSubTable!("101tdddddddd", branchAndBranchWithLink, unsupported)(table); 98 99 // No bits 100 addSubTable!("1111dddddddd", softwareInterrupt, unsupported)(table); 101 102 return table; 103 } 104 105 private mixin template decodeOpDataProcessing_RegShiftImm() { 106 mixin decodeOpDataProcessing_RegShiftReg!true; 107 } 108 109 private mixin template decodeOpDataProcessing_RegShiftReg() { 110 mixin decodeOpDataProcessing_RegShiftReg!false; 111 } 112 113 private mixin template decodeOpDataProcessing_Imm() { 114 // Decode 115 int rn = instruction.getBits(16, 19); 116 int rd = instruction.getBits(12, 15); 117 int op1 = registers.get(rn); 118 // Get op2 119 int shift = instruction.getBits(8, 11) * 2; 120 int op2 = rotateRight(instruction & 0xFF, shift); 121 int carry = shift == 0 ? registers.getFlag(CPSRFlag.C) : op2.getBit(31); 122 } 123 124 private mixin template decodeOpDataProcessing_RegShiftReg(bool immediateShift) { 125 // Decode 126 int rn = instruction.getBits(16, 19); 127 int rd = instruction.getBits(12, 15); 128 int op1 = registers.get(rn); 129 // Get op2 130 static if (immediateShift) { 131 ubyte shift = cast(ubyte) instruction.getBits(7, 11); 132 } else { 133 ubyte shift = cast(ubyte) registers.get(instruction.getBits(8, 11)); 134 } 135 int shiftType = instruction.getBits(5, 6); 136 int carry; 137 int op2 = registers.applyShift!(!immediateShift)(shiftType, shift, registers.get(instruction & 0b1111), carry); 138 } 139 140 private template dataProcessing_RegShiftImm(int code) if (code.getBits(5, 31) == 0) { 141 private alias dataProcessing_RegShiftImm = 142 dataProcessing!(decodeOpDataProcessing_RegShiftImm, code.getBits(1, 4), code.checkBit(0)); 143 } 144 145 private template dataProcessing_RegShiftReg(int code) if (code.getBits(5, 31) == 0) { 146 private alias dataProcessing_RegShiftReg = 147 dataProcessing!(decodeOpDataProcessing_RegShiftReg, code.getBits(1, 4), code.checkBit(0)); 148 } 149 150 private template dataProcessing_Imm(int code) if (code.getBits(5, 31) == 0) { 151 private alias dataProcessing_Imm = 152 dataProcessing!(decodeOpDataProcessing_Imm, code.getBits(1, 4), code.checkBit(0)); 153 } 154 155 private void dataProcessing(alias decodeOperands, int opCode: 0, bool setFlags) 156 (Registers* registers, MemoryBus* memory, int instruction) { 157 debug (outputInstructions) registers.logInstruction(instruction, "AND"); 158 mixin decodeOperands; 159 // Operation 160 int res = op1 & op2; 161 registers.set(rd, res); 162 // Flag updates 163 static if (setFlags) { 164 if (rd == Register.PC) { 165 registers.setCPSR(registers.getSPSR()); 166 } else { 167 int negative = res < 0; 168 int zero = res == 0; 169 registers.setApsrFlags(negative, zero, carry); 170 } 171 } 172 } 173 174 private void dataProcessing(alias decodeOperands, int opCode: 1, bool setFlags) 175 (Registers* registers, MemoryBus* memory, int instruction) { 176 debug (outputInstructions) registers.logInstruction(instruction, "EOR"); 177 mixin decodeOperands; 178 // Operation 179 int res = op1 ^ op2; 180 registers.set(rd, res); 181 // Flag updates 182 static if (setFlags) { 183 if (rd == Register.PC) { 184 registers.setCPSR(registers.getSPSR()); 185 } else { 186 int negative = res < 0; 187 int zero = res == 0; 188 registers.setApsrFlags(negative, zero, carry); 189 } 190 } 191 } 192 193 194 private void dataProcessing(alias decodeOperands, int opCode: 2, bool setFlags) 195 (Registers* registers, MemoryBus* memory, int instruction) { 196 debug (outputInstructions) registers.logInstruction(instruction, "SUB"); 197 mixin decodeOperands; 198 // Operation 199 int res = op1 - op2; 200 registers.set(rd, res); 201 // Flag updates 202 static if (setFlags) { 203 if (rd == Register.PC) { 204 registers.setCPSR(registers.getSPSR()); 205 } else { 206 int negative = res < 0; 207 int zero = res == 0; 208 carry = !borrowedSub(op1, op2, res); 209 int overflow = overflowedSub(op1, op2, res); 210 registers.setApsrFlags(negative, zero, carry, overflow); 211 } 212 } 213 } 214 215 private void dataProcessing(alias decodeOperands, int opCode: 3, bool setFlags) 216 (Registers* registers, MemoryBus* memory, int instruction) { 217 debug (outputInstructions) registers.logInstruction(instruction, "RSB"); 218 mixin decodeOperands; 219 // Operation 220 int res = op2 - op1; 221 registers.set(rd, res); 222 // Flag updates 223 static if (setFlags) { 224 if (rd == Register.PC) { 225 registers.setCPSR(registers.getSPSR()); 226 } else { 227 int negative = res < 0; 228 int zero = res == 0; 229 carry = !borrowedSub(op2, op1, res); 230 int overflow = overflowedSub(op2, op1, res); 231 registers.setApsrFlags(negative, zero, carry, overflow); 232 } 233 } 234 } 235 236 private void dataProcessing(alias decodeOperands, int opCode: 4, bool setFlags) 237 (Registers* registers, MemoryBus* memory, int instruction) { 238 debug (outputInstructions) registers.logInstruction(instruction, "ADD"); 239 mixin decodeOperands; 240 // Operation 241 int res = op1 + op2; 242 registers.set(rd, res); 243 // Flag updates 244 static if (setFlags) { 245 if (rd == Register.PC) { 246 registers.setCPSR(registers.getSPSR()); 247 } else { 248 int negative = res < 0; 249 int zero = res == 0; 250 carry = carriedAdd(op1, op2, res); 251 int overflow = overflowedAdd(op1, op2, res); 252 registers.setApsrFlags(negative, zero, carry, overflow); 253 } 254 } 255 } 256 257 private void dataProcessing(alias decodeOperands, int opCode: 5, bool setFlags) 258 (Registers* registers, MemoryBus* memory, int instruction) { 259 debug (outputInstructions) registers.logInstruction(instruction, "ADC"); 260 mixin decodeOperands; 261 // Operation 262 int op3 = registers.getFlag(CPSRFlag.C); 263 int tmp = op1 + op2; 264 int res = tmp + op3; 265 registers.set(rd, res); 266 // Flag updates 267 static if (setFlags) { 268 if (rd == Register.PC) { 269 registers.setCPSR(registers.getSPSR()); 270 } else { 271 int negative = res < 0; 272 int zero = res == 0; 273 carry = carriedAdd(op1, op2, tmp) || carriedAdd(tmp, op3, res); 274 int overflow = overflowedAdd(op1, op2, tmp) || overflowedAdd(tmp, op3, res); 275 registers.setApsrFlags(negative, zero, carry, overflow); 276 } 277 } 278 } 279 280 private void dataProcessing(alias decodeOperands, int opCode: 6, bool setFlags) 281 (Registers* registers, MemoryBus* memory, int instruction) { 282 debug (outputInstructions) registers.logInstruction(instruction, "SBC"); 283 mixin decodeOperands; 284 // Operation 285 int op3 = !registers.getFlag(CPSRFlag.C); 286 int tmp = op1 - op2; 287 int res = tmp - op3; 288 registers.set(rd, res); 289 // Flag updates 290 static if (setFlags) { 291 if (rd == Register.PC) { 292 registers.setCPSR(registers.getSPSR()); 293 } else { 294 int negative = res < 0; 295 int zero = res == 0; 296 carry = !borrowedSub(op1, op2, tmp) && !borrowedSub(tmp, op3, res); 297 int overflow = overflowedSub(op1, op2, tmp) || overflowedSub(tmp, op3, res); 298 registers.setApsrFlags(negative, zero, carry, overflow); 299 } 300 } 301 } 302 303 private void dataProcessing(alias decodeOperands, int opCode: 7, bool setFlags) 304 (Registers* registers, MemoryBus* memory, int instruction) { 305 debug (outputInstructions) registers.logInstruction(instruction, "RSC"); 306 mixin decodeOperands; 307 // Operation 308 int op3 = !registers.getFlag(CPSRFlag.C); 309 int tmp = op2 - op1; 310 int res = tmp - op3; 311 registers.set(rd, res); 312 // Flag updates 313 static if (setFlags) { 314 if (rd == Register.PC) { 315 registers.setCPSR(registers.getSPSR()); 316 } else { 317 int negative = res < 0; 318 int zero = res == 0; 319 carry = !borrowedSub(op2, op1, tmp) && !borrowedSub(tmp, op3, res); 320 int overflow = overflowedSub(op2, op1, tmp) || overflowedSub(tmp, op3, res); 321 registers.setApsrFlags(negative, zero, carry, overflow); 322 } 323 } 324 } 325 326 private void dataProcessing(alias decodeOperands, int opCode: 8, bool setFlags: true) 327 (Registers* registers, MemoryBus* memory, int instruction) { 328 debug (outputInstructions) registers.logInstruction(instruction, "TST"); 329 mixin decodeOperands; 330 // Operation 331 int res = op1 & op2; 332 // Flag updates 333 int negative = res < 0; 334 int zero = res == 0; 335 registers.setApsrFlags(negative, zero, carry); 336 } 337 338 private void dataProcessing(alias decodeOperands, int opCode: 9, bool setFlags: true) 339 (Registers* registers, MemoryBus* memory, int instruction) { 340 debug (outputInstructions) registers.logInstruction(instruction, "TEQ"); 341 mixin decodeOperands; 342 // Operation 343 int res = op1 ^ op2; 344 // Flag updates 345 int negative = res < 0; 346 int zero = res == 0; 347 registers.setApsrFlags(negative, zero, carry); 348 } 349 350 private void dataProcessing(alias decodeOperands, int opCode: 10, bool setFlags: true) 351 (Registers* registers, MemoryBus* memory, int instruction) { 352 debug (outputInstructions) registers.logInstruction(instruction, "CMP"); 353 mixin decodeOperands; 354 // Operation 355 int res = op1 - op2; 356 // Flag updates 357 int negative = res < 0; 358 int zero = res == 0; 359 carry = !borrowedSub(op1, op2, res); 360 int overflow = overflowedSub(op1, op2, res); 361 registers.setApsrFlags(negative, zero, carry, overflow); 362 } 363 364 private void dataProcessing(alias decodeOperands, int opCode: 11, bool setFlags: true) 365 (Registers* registers, MemoryBus* memory, int instruction) { 366 debug (outputInstructions) registers.logInstruction(instruction, "CMN"); 367 mixin decodeOperands; 368 // Operation 369 int res = op1 + op2; 370 // Flag updates 371 int negative = res < 0; 372 int zero = res == 0; 373 carry = carriedAdd(op1, op2, res); 374 int overflow = overflowedAdd(op1, op2, res); 375 registers.setApsrFlags(negative, zero, carry, overflow); 376 } 377 378 private void dataProcessing(alias decodeOperands, int opCode: 12, bool setFlags) 379 (Registers* registers, MemoryBus* memory, int instruction) { 380 debug (outputInstructions) registers.logInstruction(instruction, "ORR"); 381 mixin decodeOperands; 382 // Operation 383 int res = op1 | op2; 384 registers.set(rd, res); 385 // Flag updates 386 static if (setFlags) { 387 if (rd == Register.PC) { 388 registers.setCPSR(registers.getSPSR()); 389 } else { 390 int negative = res < 0; 391 int zero = res == 0; 392 registers.setApsrFlags(negative, zero, carry); 393 } 394 } 395 } 396 397 private void dataProcessing(alias decodeOperands, int opCode: 13, bool setFlags) 398 (Registers* registers, MemoryBus* memory, int instruction) { 399 debug (outputInstructions) registers.logInstruction(instruction, "MOV"); 400 mixin decodeOperands; 401 // Operation 402 int res = op2; 403 registers.set(rd, res); 404 // Flag updates 405 static if (setFlags) { 406 if (rd == Register.PC) { 407 registers.setCPSR(registers.getSPSR()); 408 } else { 409 int negative = res < 0; 410 int zero = res == 0; 411 registers.setApsrFlags(negative, zero, carry); 412 } 413 } 414 } 415 416 private void dataProcessing(alias decodeOperands, int opCode: 14, bool setFlags) 417 (Registers* registers, MemoryBus* memory, int instruction) { 418 debug (outputInstructions) registers.logInstruction(instruction, "BIC"); 419 mixin decodeOperands; 420 // Operation 421 int res = op1 & ~op2; 422 registers.set(rd, res); 423 // Flag updates 424 static if (setFlags) { 425 if (rd == Register.PC) { 426 registers.setCPSR(registers.getSPSR()); 427 } else { 428 int negative = res < 0; 429 int zero = res == 0; 430 registers.setApsrFlags(negative, zero, carry); 431 } 432 } 433 } 434 435 private void dataProcessing(alias decodeOperands, int opCode: 15, bool setFlags) 436 (Registers* registers, MemoryBus* memory, int instruction) { 437 debug (outputInstructions) registers.logInstruction(instruction, "MVN"); 438 mixin decodeOperands; 439 // Operation 440 int res = ~op2; 441 registers.set(rd, res); 442 // Flag updates 443 static if (setFlags) { 444 if (rd == Register.PC) { 445 registers.setCPSR(registers.getSPSR()); 446 } else { 447 int negative = res < 0; 448 int zero = res == 0; 449 registers.setApsrFlags(negative, zero, carry); 450 } 451 } 452 } 453 454 @("unsupported") 455 private template dataProcessing(alias decodeOperands, int opCode, bool setFlags) 456 if (opCode >= 8 && opCode <= 11 && !setFlags) { 457 private alias dataProcessing = unsupported; 458 } 459 460 private mixin template decodeOpPsrTransfer_Imm() { 461 int op = rotateRight(instruction & 0xFF, instruction.getBits(8, 11) * 2); 462 } 463 464 private mixin template decodeOpPsrTransfer_Reg() { 465 int op = registers.get(instruction & 0xF); 466 } 467 468 private template psrTransfer_Imm(int code) if (code.getBits(1, 31) == 0) { 469 private alias psrTransfer_Imm = psrTransfer!(decodeOpPsrTransfer_Imm, code.checkBit(0), true); 470 } 471 472 private template psrTransfer_Reg(int code) if (code.getBits(2, 31) == 0) { 473 private alias psrTransfer_Reg = psrTransfer!(decodeOpPsrTransfer_Reg, code.checkBit(1), code.checkBit(0)); 474 } 475 476 private void psrTransfer(alias decodeOperand, bool useSPSR: false, bool notLoad: false)(Registers* registers, MemoryBus* memory, int instruction) 477 if (__traits(isSame, decodeOperand, decodeOpPsrTransfer_Reg)) { 478 debug (outputInstructions) registers.logInstruction(instruction, "MRS"); 479 int rd = instruction.getBits(12, 15); 480 registers.set(rd, registers.getCPSR()); 481 } 482 483 private void psrTransfer(alias decodeOperand, bool useSPSR: false, bool notLoad: true)(Registers* registers, MemoryBus* memory, int instruction) { 484 debug (outputInstructions) registers.logInstruction(instruction, "MSR"); 485 mixin decodeOperand; 486 int mask = instruction.getPsrMask() & (0xF0000000 | (registers.mode != Mode.USER ? 0xFF : 0)); 487 int cpsr = registers.getCPSR(); 488 registers.setCPSR(cpsr & ~mask | op & mask); 489 } 490 491 private void psrTransfer(alias decodeOperand, bool useSPSR: true, bool notLoad: false)(Registers* registers, MemoryBus* memory, int instruction) 492 if (__traits(isSame, decodeOperand, decodeOpPsrTransfer_Reg)) { 493 debug (outputInstructions) registers.logInstruction(instruction, "MRS"); 494 int rd = instruction.getBits(12, 15); 495 registers.set(rd, registers.getSPSR()); 496 } 497 498 private void psrTransfer(alias decodeOperand, bool useSPSR: true, bool notLoad: true)(Registers* registers, MemoryBus* memory, int instruction) { 499 debug (outputInstructions) registers.logInstruction(instruction, "MSR"); 500 mixin decodeOperand; 501 int mask = instruction.getPsrMask() & 0xF00000FF; 502 int spsr = registers.getSPSR(); 503 registers.setSPSR(spsr & ~mask | op & mask); 504 } 505 506 @("unsupported") 507 private template psrTransfer(alias decodeOperand, bool useSPSR, bool notLoad) 508 if (!notLoad && !__traits(isSame, decodeOperand, decodeOpPsrTransfer_Reg)) { 509 private alias psrTransfer = unsupported; 510 } 511 512 private int getPsrMask(int instruction) { 513 int mask = 0; 514 if (instruction.checkBit(19)) { 515 // flags 516 mask |= 0xFF000000; 517 } 518 if (instruction.checkBit(18)) { 519 // status 520 mask |= 0xFF0000; 521 } 522 if (instruction.checkBit(17)) { 523 // extension 524 mask |= 0xFF00; 525 } 526 if (instruction.checkBit(16)) { 527 // control 528 mask |= 0xFF; 529 } 530 return mask; 531 } 532 533 private void branchAndExchange()(Registers* registers, MemoryBus* memory, int instruction) { 534 debug (outputInstructions) registers.logInstruction(instruction, "BX"); 535 int address = registers.get(instruction & 0xF); 536 if (address & 0b1) { 537 registers.setFlag(CPSRFlag.T, Set.THUMB); 538 } 539 registers.setPC(address & ~1); 540 } 541 542 private mixin template decodeOpMultiply() { 543 int rd = instruction.getBits(16, 19); 544 int op2 = registers.get(instruction.getBits(8, 11)); 545 int op1 = registers.get(instruction & 0xF); 546 } 547 548 private template multiply_Int(int code) if (code.getBits(2, 31) == 0) { 549 private alias multiply_Int = multiply!(false, false, code.checkBit(1), code.checkBit(0)); 550 } 551 552 private template multiply_Long(int code) if (code.getBits(3, 31) == 0) { 553 private alias multiply_Long = multiply!(true, code.checkBit(2), code.checkBit(1), code.checkBit(0)); 554 } 555 556 private void multiply(bool long_: false, bool notUnsigned: false, bool accumulate: false, bool setFlags) 557 (Registers* registers, MemoryBus* memory, int instruction) { 558 debug (outputInstructions) registers.logInstruction(instruction, "MUL"); 559 mixin decodeOpMultiply; 560 int res = op1 * op2; 561 registers.setMultiplyIntResult!setFlags(rd, res); 562 } 563 564 private void multiply(bool long_: false, bool notUnsigned: false, bool accumulate: true, bool setFlags) 565 (Registers* registers, MemoryBus* memory, int instruction) { 566 debug (outputInstructions) registers.logInstruction(instruction, "MLA"); 567 mixin decodeOpMultiply; 568 int op3 = registers.get(instruction.getBits(12, 15)); 569 int res = op1 * op2 + op3; 570 registers.setMultiplyIntResult!setFlags(rd, res); 571 } 572 573 private void multiply(bool long_: true, bool notUnsigned: false, bool accumulate: false, bool setFlags) 574 (Registers* registers, MemoryBus* memory, int instruction) { 575 debug (outputInstructions) registers.logInstruction(instruction, "UMULL"); 576 mixin decodeOpMultiply; 577 int rn = instruction.getBits(12, 15); 578 ulong res = op1.ucast() * op2.ucast(); 579 registers.setMultiplyLongResult!setFlags(rd, rn, res); 580 } 581 582 private void multiply(bool long_: true, bool notUnsigned: false, bool accumulate: true, bool setFlags) 583 (Registers* registers, MemoryBus* memory, int instruction) { 584 debug (outputInstructions) registers.logInstruction(instruction, "UMLAL"); 585 mixin decodeOpMultiply; 586 int rn = instruction.getBits(12, 15); 587 ulong op3 = ucast(registers.get(rd)) << 32 | ucast(registers.get(rn)); 588 ulong res = op1.ucast() * op2.ucast() + op3; 589 registers.setMultiplyLongResult!setFlags(rd, rn, res); 590 } 591 592 private void multiply(bool long_: true, bool notUnsigned: true, bool accumulate: false, bool setFlags) 593 (Registers* registers, MemoryBus* memory, int instruction) { 594 debug (outputInstructions) registers.logInstruction(instruction, "SMULL"); 595 mixin decodeOpMultiply; 596 int rn = instruction.getBits(12, 15); 597 long res = cast(long) op1 * cast(long) op2; 598 registers.setMultiplyLongResult!setFlags(rd, rn, res); 599 } 600 601 private void multiply(bool long_: true, bool notUnsigned: true, bool accumulate: true, bool setFlags) 602 (Registers* registers, MemoryBus* memory, int instruction) { 603 debug (outputInstructions) registers.logInstruction(instruction, "SMLAL"); 604 mixin decodeOpMultiply; 605 int rn = instruction.getBits(12, 15); 606 long op3 = ucast(registers.get(rd)) << 32 | ucast(registers.get(rn)); 607 long res = cast(long) op1 * cast(long) op2 + op3; 608 registers.setMultiplyLongResult!setFlags(rd, rn, res); 609 } 610 611 @("unsupported") 612 private template multiply(bool long_, bool notUnsigned, bool accumulate, bool setFlags) 613 if (!long_ && notUnsigned) { 614 private alias multiply = unsupported; 615 } 616 617 private void setMultiplyIntResult(bool setFlags)(Registers* registers, int rd, int res) { 618 registers.set(rd, res); 619 static if (setFlags) { 620 registers.setApsrFlags(res < 0, res == 0); 621 } 622 } 623 624 private void setMultiplyLongResult(bool setFlags)(Registers* registers, int rd, int rn, long res) { 625 int resLo = cast(int) res; 626 int resHi = cast(int) (res >> 32); 627 registers.set(rn, resLo); 628 registers.set(rd, resHi); 629 static if (setFlags) { 630 registers.setApsrFlags(res < 0, res == 0); 631 } 632 } 633 634 private template singleDataSwap(int code) if (code.getBits(1, 31) == 0) { 635 private alias singleDataSwap = singleDataSwap!(code.checkBit(0)); 636 } 637 638 private void singleDataSwap(bool byteQty)(Registers* registers, MemoryBus* memory, int instruction) { 639 debug (outputInstructions) registers.logInstruction(instruction, "SWP"); 640 // Decode operands 641 int rn = instruction.getBits(16, 19); 642 int rd = instruction.getBits(12, 15); 643 int rm = instruction & 0xF; 644 int address = registers.get(rn); 645 // Do memory swap 646 static if (byteQty) { 647 int b = memory.get!byte(address) & 0xFF; 648 memory.set!byte(address, cast(byte) registers.get(rm)); 649 registers.set(rd, b); 650 } else { 651 int w = address.rotateRead(memory.get!int(address)); 652 memory.set!int(address, registers.get(rm)); 653 registers.set(rd, w); 654 } 655 } 656 657 private template halfwordAndSignedDataTransfer_Reg(int code) if (code.getBits(6, 31) == 0) { 658 private alias halfwordAndSignedDataTransfer_Reg = halfwordAndSignedDataTransfer!( 659 code.checkBit(5), code.checkBit(4), false, code.checkBit(3), 660 code.checkBit(2), code.getBit(1), code.getBit(0) 661 ); 662 } 663 664 private template halfwordAndSignedDataTransfer_Imm(int code) if (code.getBits(6, 31) == 0) { 665 private alias halfwordAndSignedDataTransfer_Imm = halfwordAndSignedDataTransfer!( 666 code.checkBit(5), code.checkBit(4), true, code.checkBit(3), 667 code.checkBit(2), code.getBit(1), code.getBit(0) 668 ); 669 } 670 671 private void halfwordAndSignedDataTransfer(bool preIncr, bool upIncr, bool immediate, 672 bool writeBack, bool load, bool signed, bool half)(Registers* registers, MemoryBus* memory, int instruction) 673 if ((!load || half || signed) && (load || half && !signed) && (preIncr || !writeBack)) { 674 // Decode operands 675 int rn = instruction.getBits(16, 19); 676 int rd = instruction.getBits(12, 15); 677 static if (immediate) { 678 int upperOffset = instruction.getBits(8, 11); 679 int lowerOffset = instruction & 0xF; 680 int offset = upperOffset << 4 | lowerOffset; 681 } else { 682 int offset = registers.get(instruction & 0xF); 683 } 684 int address = registers.get(rn); 685 // Do pre-increment if needed 686 static if (preIncr) { 687 static if (upIncr) { 688 address += offset; 689 } else { 690 address -= offset; 691 } 692 } 693 // Read or write memory 694 static if (load) { 695 static if (half) { 696 static if (signed) { 697 debug (outputInstructions) registers.logInstruction(instruction, "LDRSH"); 698 registers.set(rd, address.rotateReadSigned(memory.get!short(address))); 699 } else { 700 debug (outputInstructions) registers.logInstruction(instruction, "LDRH"); 701 registers.set(rd, address.rotateRead(memory.get!short(address))); 702 } 703 } else { 704 static if (signed) { 705 debug (outputInstructions) registers.logInstruction(instruction, "LDRSB"); 706 registers.set(rd, memory.get!byte(address)); 707 } else { 708 static assert (0); 709 } 710 } 711 } else { 712 static if (half && !signed) { 713 debug (outputInstructions) registers.logInstruction(instruction, "STRH"); 714 memory.set!short(address, cast(short) registers.get(rd)); 715 } else { 716 static assert (0); 717 } 718 } 719 // Do post-increment and write back if needed 720 static if (preIncr) { 721 static if (writeBack) { 722 registers.set(rn, address); 723 } 724 } else { 725 static if (upIncr) { 726 address += offset; 727 } else { 728 address -= offset; 729 } 730 // Always do write back in post increment, the flag should be 0 731 static if (writeBack) { 732 static assert (0); 733 } 734 registers.set(rn, address); 735 } 736 } 737 738 @("unsupported") 739 private template halfwordAndSignedDataTransfer(bool preIncr, bool upIncr, bool immediate, 740 bool writeBack, bool load, bool signed, bool half) 741 if (load && !half && !signed || 742 !load && (!half || signed) || 743 !preIncr && writeBack) { 744 private alias halfwordAndSignedDataTransfer = unsupported; 745 } 746 747 private template singleDataTransfer_Imm(int code) if (code.getBits(5, 31) == 0) { 748 private alias singleDataTransfer_Imm = singleDataTransfer!( 749 false, code.checkBit(4), code.checkBit(3), code.checkBit(2), 750 code.checkBit(1), code.checkBit(0) 751 ); 752 } 753 754 private template singleDataTransfer_Reg(int code) if (code.getBits(5, 31) == 0) { 755 private alias singleDataTransfer_Reg = singleDataTransfer!( 756 true, code.checkBit(4), code.checkBit(3), code.checkBit(2), 757 code.checkBit(1), code.checkBit(0) 758 ); 759 } 760 761 private void singleDataTransfer(bool notImmediate, bool preIncr, bool upIncr, bool byteQty, 762 bool writeBack, bool load)(Registers* registers, MemoryBus* memory, int instruction) { 763 // Decode operands 764 int rn = instruction.getBits(16, 19); 765 int rd = instruction.getBits(12, 15); 766 static if (notImmediate) { 767 ubyte shift = cast(ubyte) instruction.getBits(7, 11); 768 int shiftType = instruction.getBits(5, 6); 769 int carry; 770 int offset = registers.applyShift!false(shiftType, shift, registers.get(instruction & 0b1111), carry); 771 } else { 772 int offset = instruction & 0xFFF; 773 } 774 int address = registers.get(rn); 775 // Do pre-increment if needed 776 static if (preIncr) { 777 static if (upIncr) { 778 address += offset; 779 } else { 780 address -= offset; 781 } 782 } 783 // Read or write memory 784 static if (load) { 785 static if (byteQty) { 786 debug (outputInstructions) registers.logInstruction(instruction, "LDRB"); 787 registers.set(rd, memory.get!byte(address) & 0xFF); 788 } else { 789 debug (outputInstructions) registers.logInstruction(instruction, "LDR"); 790 int data = address.rotateRead(memory.get!int(address)); 791 if (rd == Register.PC) { 792 data &= ~0b11; 793 } 794 registers.set(rd, data); 795 } 796 } else { 797 static if (byteQty) { 798 debug (outputInstructions) registers.logInstruction(instruction, "STRB"); 799 memory.set!byte(address, cast(byte) registers.get(rd)); 800 } else { 801 debug (outputInstructions) registers.logInstruction(instruction, "STR"); 802 memory.set!int(address, registers.get(rd)); 803 } 804 } 805 // Do post-increment and write back if needed 806 static if (preIncr) { 807 static if (writeBack) { 808 registers.set(rn, address); 809 } 810 } else { 811 static if (upIncr) { 812 address += offset; 813 } else { 814 address -= offset; 815 } 816 // Always do write back in post increment 817 registers.set(rn, address); 818 } 819 } 820 821 private static string genBlockDataTransferOperation(bool preIncr, bool load) { 822 auto memoryOp = load ? "registers.set(mode, i, memory.get!int(address));\n" : 823 "memory.set!int(address, registers.get(mode, i));\n"; 824 auto incr = "address += 4;\n"; 825 auto singleOp = preIncr ? incr ~ memoryOp : memoryOp ~ incr; 826 auto ops = 827 `foreach (i; 0 .. 15) { 828 if (registerList.checkBit(i)) { 829 ` ~ singleOp ~ ` 830 } 831 }`; 832 // Handle PC specially because we need to align it on load 833 auto pcOp = load ? "registers.set(mode, i, memory.get!int(address) & ~0b11);\n" : memoryOp; 834 pcOp = preIncr ? incr ~ pcOp : pcOp ~ incr; 835 ops ~= ` 836 immutable i = 15; 837 if (registerList.checkBit(i)) { 838 ` ~ pcOp ~ ` 839 }`; 840 return ops; 841 } 842 843 private template blockDataTransfer(int code) if (code.getBits(5, 31) == 0) { 844 private alias blockDataTransfer = blockDataTransfer!( 845 code.checkBit(4), code.checkBit(3), code.checkBit(2), 846 code.checkBit(1), code.checkBit(0) 847 ); 848 } 849 850 private void blockDataTransfer(bool preIncr, bool upIncr, bool loadPSR, 851 bool writeBack, bool load)(Registers* registers, MemoryBus* memory, int instruction) { 852 static if (load) { 853 debug (outputInstructions) registers.logInstruction(instruction, "LDM"); 854 } else { 855 debug (outputInstructions) registers.logInstruction(instruction, "STM"); 856 } 857 // Decode operands 858 int rn = instruction.getBits(16, 19); 859 int registerList = instruction & 0xFFFF; 860 // Force user mode if flag is set and not loading PC 861 static if (loadPSR) { 862 Mode mode = Mode.USER; 863 static if (load) { 864 if (registerList.checkBit(15)) { 865 mode = registers.mode; 866 } 867 } 868 } else { 869 Mode mode = registers.mode; 870 } 871 // Memory transfer 872 int baseAddress = registers.get(rn); 873 int address; 874 static if (upIncr) { 875 address = baseAddress; 876 mixin (genBlockDataTransferOperation(preIncr, load)); 877 } else { 878 baseAddress -= 4 * registerList.popcnt(); 879 address = baseAddress; 880 // Load order is always in increasing memory order, even when 881 // using down-increment. This means we use bit counting to find 882 // the final address and use up-increments instead. This 883 // does reverse the pre-increment behaviour though 884 mixin (genBlockDataTransferOperation(!preIncr, load)); 885 // The address to write back is the corrected base 886 address = baseAddress; 887 } 888 // Loading and load PSR flag is set, restore CPSR 889 static if (loadPSR && load) { 890 if (registerList.checkBit(15)) { 891 registers.setCPSR(registers.getSPSR()); 892 } 893 } 894 // Writeback the new address into the base if needed 895 static if (writeBack) { 896 registers.set(mode, rn, address); 897 } 898 } 899 900 private void branchAndBranchWithLink(int code: 0)(Registers* registers, MemoryBus* memory, int instruction) { 901 debug (outputInstructions) registers.logInstruction(instruction, "B"); 902 int offset = instruction & 0xFFFFFF; 903 // sign extend the offset 904 offset <<= 8; 905 offset >>= 8; 906 int pc = registers.getPC(); 907 registers.setPC(pc + offset * 4); 908 } 909 910 private void branchAndBranchWithLink(int code: 1)(Registers* registers, MemoryBus* memory, int instruction) { 911 debug (outputInstructions) registers.logInstruction(instruction, "BL"); 912 int offset = instruction & 0xFFFFFF; 913 // sign extend the offset 914 offset <<= 8; 915 offset >>= 8; 916 int pc = registers.getPC(); 917 registers.set(Register.LR, pc - 4); 918 registers.setPC(pc + offset * 4); 919 } 920 921 private void softwareInterrupt()(Registers* registers, MemoryBus* memory, int instruction) { 922 debug (outputInstructions) registers.logInstruction(instruction, "SWI"); 923 registers.setSPSR(Mode.SUPERVISOR, registers.getCPSR()); 924 registers.set(Mode.SUPERVISOR, Register.LR, registers.getPC() - 4); 925 registers.setPC(0x8); 926 registers.setFlag(CPSRFlag.I, 1); 927 registers.setMode(Mode.SUPERVISOR); 928 } 929 930 private void undefined(Registers* registers, MemoryBus* memory, int instruction) { 931 debug (outputInstructions) registers.logInstruction(instruction, "UND"); 932 registers.setSPSR(Mode.UNDEFINED, registers.getCPSR()); 933 registers.set(Mode.UNDEFINED, Register.LR, registers.getPC() - 4); 934 registers.setPC(0x4); 935 registers.setFlag(CPSRFlag.I, 1); 936 registers.setMode(Mode.UNDEFINED); 937 } 938 939 private void unsupported(Registers* registers, MemoryBus* memory, int instruction) { 940 throw new UnsupportedARMInstructionException(registers.getExecutedPC(), instruction); 941 } 942 943 public class UnsupportedARMInstructionException : Exception { 944 private this(int address, int instruction) { 945 super(format("This ARM instruction is unsupported by the implementation\n%08x: %08x", address, instruction)); 946 } 947 }