diff options
author | StapleButter <thetotalworm@gmail.com> | 2017-03-16 23:01:22 +0100 |
---|---|---|
committer | StapleButter <thetotalworm@gmail.com> | 2017-03-16 23:01:22 +0100 |
commit | 8a4ed8f41ca54164fdb335343461ab5f9c3bd87f (patch) | |
tree | 28ba71576603fef73dfcce5db33e157ec236e6c5 /src/ARM.cpp | |
parent | 10ca9b6f7f20f88dfcdfdf680daf1b04cb7f22c5 (diff) |
reorganize repo, move shit around
Diffstat (limited to 'src/ARM.cpp')
-rw-r--r-- | src/ARM.cpp | 411 |
1 files changed, 411 insertions, 0 deletions
diff --git a/src/ARM.cpp b/src/ARM.cpp new file mode 100644 index 0000000..536c78c --- /dev/null +++ b/src/ARM.cpp @@ -0,0 +1,411 @@ +/* + Copyright 2016-2017 StapleButter + + This file is part of melonDS. + + melonDS is free software: you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation, either version 3 of the License, or (at your option) + any later version. + + melonDS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with melonDS. If not, see http://www.gnu.org/licenses/. +*/ + +#include <stdio.h> +#include "NDS.h" +#include "ARM.h" +#include "ARMInterpreter.h" +#include "GPU3D.h" + + +u32 ARM::ConditionTable[16] = +{ + 0xF0F0, // EQ + 0x0F0F, // NE + 0xCCCC, // CS + 0x3333, // CC + 0xFF00, // MI + 0x00FF, // PL + 0xAAAA, // VS + 0x5555, // VC + 0x0C0C, // HI + 0xF3F3, // LS + 0xAA55, // GE + 0x55AA, // LT + 0x0A05, // GT + 0xF5FA, // LE + 0xFFFF, // AL + 0x0000 // NE +}; + + +ARM::ARM(u32 num) +{ + // well uh + Num = num; + + for (int i = 0; i < 16; i++) + { + Waitstates[0][i] = 1; + Waitstates[1][i] = 1; + Waitstates[2][i] = 1; + Waitstates[3][i] = 1; + } + + if (!num) + { + // ARM9 + Waitstates[0][0x2] = 1; // main RAM timing, assuming cache hit + Waitstates[0][0x3] = 4; + Waitstates[0][0x4] = 4; + Waitstates[0][0x5] = 5; + Waitstates[0][0x6] = 5; + Waitstates[0][0x7] = 4; + Waitstates[0][0x8] = 19; + Waitstates[0][0x9] = 19; + Waitstates[0][0xF] = 4; + + Waitstates[1][0x2] = 1; + Waitstates[1][0x3] = 8; + Waitstates[1][0x4] = 8; + Waitstates[1][0x5] = 10; + Waitstates[1][0x6] = 10; + Waitstates[1][0x7] = 8; + Waitstates[1][0x8] = 38; + Waitstates[1][0x9] = 38; + Waitstates[1][0xF] = 8; + + Waitstates[2][0x2] = 1; + Waitstates[2][0x3] = 2; + Waitstates[2][0x4] = 2; + Waitstates[2][0x5] = 2; + Waitstates[2][0x6] = 2; + Waitstates[2][0x7] = 2; + Waitstates[2][0x8] = 12; + Waitstates[2][0x9] = 12; + Waitstates[2][0xA] = 20; + Waitstates[2][0xF] = 2; + + Waitstates[3][0x2] = 1; + Waitstates[3][0x3] = 2; + Waitstates[3][0x4] = 2; + Waitstates[3][0x5] = 4; + Waitstates[3][0x6] = 4; + Waitstates[3][0x7] = 2; + Waitstates[3][0x8] = 24; + Waitstates[3][0x9] = 24; + Waitstates[3][0xA] = 20; + Waitstates[3][0xF] = 2; + } + else + { + // ARM7 + Waitstates[0][0x0] = 1; + Waitstates[0][0x2] = 1; + Waitstates[0][0x3] = 1; + Waitstates[0][0x4] = 1; + Waitstates[0][0x6] = 1; + Waitstates[0][0x8] = 6; + Waitstates[0][0x9] = 6; + + Waitstates[1][0x0] = 1; + Waitstates[1][0x2] = 2; + Waitstates[1][0x3] = 1; + Waitstates[1][0x4] = 1; + Waitstates[1][0x6] = 2; + Waitstates[1][0x8] = 12; + Waitstates[1][0x9] = 12; + + Waitstates[2][0x0] = 1; + Waitstates[2][0x2] = 1; + Waitstates[2][0x3] = 1; + Waitstates[2][0x4] = 1; + Waitstates[2][0x6] = 1; + Waitstates[2][0x8] = 6; + Waitstates[2][0x9] = 6; + Waitstates[2][0xA] = 10; + + Waitstates[3][0x0] = 1; + Waitstates[3][0x2] = 2; + Waitstates[3][0x3] = 1; + Waitstates[3][0x4] = 1; + Waitstates[3][0x6] = 2; + Waitstates[3][0x8] = 12; + Waitstates[3][0x9] = 12; + Waitstates[3][0xA] = 10; + } +} + +ARM::~ARM() +{ + // dorp +} + +void ARM::Reset() +{ + Cycles = 0; + Halted = 0; + + for (int i = 0; i < 16; i++) + R[i] = 0; + + CPSR = 0x000000D3; + + ExceptionBase = Num ? 0x00000000 : 0xFFFF0000; + + // zorp + JumpTo(ExceptionBase); +} + +void ARM::JumpTo(u32 addr, bool restorecpsr) +{ + if (restorecpsr) + { + RestoreCPSR(); + + if (CPSR & 0x20) addr |= 0x1; + else addr &= ~0x1; + } + + if (addr & 0x1) + { + addr &= ~0x1; + R[15] = addr+2; + NextInstr[0] = CodeRead16(addr); + NextInstr[1] = CodeRead16(addr+2); + CPSR |= 0x20; + } + else + { + addr &= ~0x3; + R[15] = addr+4; + NextInstr[0] = CodeRead32(addr); + NextInstr[1] = CodeRead32(addr+4); + CPSR &= ~0x20; + } +} + +void ARM::RestoreCPSR() +{ + u32 oldcpsr = CPSR; + + switch (CPSR & 0x1F) + { + case 0x11: + CPSR = R_FIQ[7]; + break; + + case 0x12: + CPSR = R_IRQ[2]; + break; + + case 0x13: + CPSR = R_SVC[2]; + break; + + case 0x17: + CPSR = R_ABT[2]; + break; + + case 0x1B: + CPSR = R_UND[2]; + break; + + default: + printf("!! attempt to restore CPSR under bad mode %02X, %08X\n", CPSR&0x1F, R[15]); + break; + } + + UpdateMode(oldcpsr, CPSR); +} + +void ARM::UpdateMode(u32 oldmode, u32 newmode) +{ + u32 temp; + #define SWAP(a, b) temp = a; a = b; b = temp; + + if ((oldmode & 0x1F) == (newmode & 0x1F)) return; + + switch (oldmode & 0x1F) + { + case 0x11: + SWAP(R[8], R_FIQ[0]); + SWAP(R[9], R_FIQ[1]); + SWAP(R[10], R_FIQ[2]); + SWAP(R[11], R_FIQ[3]); + SWAP(R[12], R_FIQ[4]); + SWAP(R[13], R_FIQ[5]); + SWAP(R[14], R_FIQ[6]); + break; + + case 0x12: + SWAP(R[13], R_IRQ[0]); + SWAP(R[14], R_IRQ[1]); + break; + + case 0x13: + SWAP(R[13], R_SVC[0]); + SWAP(R[14], R_SVC[1]); + break; + + case 0x17: + SWAP(R[13], R_ABT[0]); + SWAP(R[14], R_ABT[1]); + break; + + case 0x1B: + SWAP(R[13], R_UND[0]); + SWAP(R[14], R_UND[1]); + break; + } + + switch (newmode & 0x1F) + { + case 0x11: + SWAP(R[8], R_FIQ[0]); + SWAP(R[9], R_FIQ[1]); + SWAP(R[10], R_FIQ[2]); + SWAP(R[11], R_FIQ[3]); + SWAP(R[12], R_FIQ[4]); + SWAP(R[13], R_FIQ[5]); + SWAP(R[14], R_FIQ[6]); + break; + + case 0x12: + SWAP(R[13], R_IRQ[0]); + SWAP(R[14], R_IRQ[1]); + break; + + case 0x13: + SWAP(R[13], R_SVC[0]); + SWAP(R[14], R_SVC[1]); + break; + + case 0x17: + SWAP(R[13], R_ABT[0]); + SWAP(R[14], R_ABT[1]); + break; + + case 0x1B: + SWAP(R[13], R_UND[0]); + SWAP(R[14], R_UND[1]); + break; + } + + #undef SWAP +} + +void ARM::TriggerIRQ() +{ + if (CPSR & 0x80) + return; + + u32 oldcpsr = CPSR; + CPSR &= ~0xFF; + CPSR |= 0xD2; + UpdateMode(oldcpsr, CPSR); + + R_IRQ[2] = oldcpsr; + R[14] = R[15] + (oldcpsr & 0x20 ? 2 : 0); + JumpTo(ExceptionBase + 0x18); +} + +s32 ARM::Execute() +{ + if (Halted) + { + if (NDS::HaltInterrupted(Num)) + { + Halted = 0; + if (NDS::IME[Num]&1) + TriggerIRQ(); + } + else + { + Cycles = CyclesToRun; + GPU3D::Run(CyclesToRun >> 1); + return Cycles; + } + } + + Cycles = 0; + s32 lastcycles = 0; + u32 addr = R[15] - (CPSR&0x20 ? 4:8); + u32 cpsr = CPSR; + + while (Cycles < CyclesToRun) + { + //if(Num==1)printf("%08X %08X\n", R[15] - (CPSR&0x20 ? 4:8), NextInstr); + + if (CPSR & 0x20) // THUMB + { + // prefetch + R[15] += 2; + CurInstr = NextInstr[0]; + NextInstr[0] = NextInstr[1]; + NextInstr[1] = CodeRead16(R[15]); + + // actually execute + u32 icode = (CurInstr >> 6); + ARMInterpreter::THUMBInstrTable[icode](this); + } + else + { + // prefetch + R[15] += 4; + CurInstr = NextInstr[0]; + NextInstr[0] = NextInstr[1]; + NextInstr[1] = CodeRead32(R[15]); + + // actually execute + if (CheckCondition(CurInstr >> 28)) + { + u32 icode = ((CurInstr >> 4) & 0xF) | ((CurInstr >> 16) & 0xFF0); + ARMInterpreter::ARMInstrTable[icode](this); + } + else if ((CurInstr & 0xFE000000) == 0xFA000000) + { + ARMInterpreter::A_BLX_IMM(this); + } + } + + //if (R[15]==0x037F9364) printf("R8=%08X R9=%08X\n", R[8], R[9]); + + // gross hack + // TODO, though: move timer code here too? + // quick testing shows that moving this to the NDS loop doesn't really slow things down + if (Num==0) + { + s32 diff = Cycles - lastcycles; + GPU3D::Run(diff >> 1); + lastcycles = Cycles - (diff&1); + } + + // TODO optimize this shit!!! + if (Halted) + { + if (Halted == 1) + Cycles = CyclesToRun; + break; + } + if (NDS::HaltInterrupted(Num)) + { + if (NDS::IME[Num]&1) + TriggerIRQ(); + } + + // temp. debug cruft + addr = R[15] - (CPSR&0x20 ? 4:8); + cpsr = CPSR; + } + + if (Halted == 2) + Halted = 0; + + return Cycles; +} |