diff options
author | StapleButter <thetotalworm@gmail.com> | 2017-01-22 20:34:59 +0100 |
---|---|---|
committer | StapleButter <thetotalworm@gmail.com> | 2017-01-22 20:34:59 +0100 |
commit | ac8936539eed2aa5b8a32761fd5a064110139608 (patch) | |
tree | 364936efb028aa3ef1c9f6d5890ac71139f0695b | |
parent | 62ed28d5c8a6af554f4af9d3dd5853b656174e55 (diff) |
some attempt at cart support
-rw-r--r-- | ARM.cpp | 34 | ||||
-rw-r--r-- | DMA.cpp | 16 | ||||
-rw-r--r-- | GPU2D.cpp | 2 | ||||
-rw-r--r-- | NDS.cpp | 239 | ||||
-rw-r--r-- | NDS.h | 9 | ||||
-rw-r--r-- | NDSCart.cpp | 438 | ||||
-rw-r--r-- | NDSCart.h | 47 | ||||
-rw-r--r-- | RTC.cpp | 2 | ||||
-rw-r--r-- | melonDS.depend | 23 |
9 files changed, 642 insertions, 168 deletions
@@ -290,40 +290,6 @@ s32 ARM::Execute(s32 cycles) TriggerIRQ(); } - // R1=X R2=Y - //if (R[15]==0x02328E88) - // printf("hah! %04X %08X %08X %08X\n", Read16(R[0]+4), R[1], R[2], - // Read32(R[13]+0x18+16+4)); - /*if (R[15]==0x02328DA6) - printf("derpo %08X %08X %08X %08X %08X %08X | %08X\n", R[0], R[1], R[2], R[3], - Read32(R[13]+0x40+0), Read32(R[13]+0x40+4), R[14]);*/ - - /*if (R[15]==0x02328C64) - printf("derpo %08X %08X %08X %08X %08X %08X %08X %08X | %08X | %04X %04X\n", R[0], R[1], R[2], R[3], - Read32(R[13]+0x40+0), Read32(R[13]+0x40+4), Read32(R[13]+0x40+8), Read32(R[13]+0x40+12), R[14], - Read16(R[0]+8), Read16(R[0]+12));*/ - - /*if (R[15]==0x023290B2) - printf("derpo %08X %08X %08X %08X | %08X\n", R[0], R[1], R[2], R[3], - R[14]); - - if (R[15]==0x23290DE) - printf("!!!!! %08X %04X %04X %08X %08X %08X %08X\n", R[3], Read16(R[3]), Read16(R[3]+2), R[2], - Read32(0x023A6184+0), Read32(0x023A6184+4), Read32(0x023A6184+8)); - if (R[15]==0x23290EA) - printf("!!!!! %08X %08X\n", R[2], R[3]); - - if (R[15]==0x2328C80) - printf("STRING SIZE=%08X\n", R[0]); - if (R[15]==0x2328CC2) - printf("SUMLOL=%08X %08X %08X\n", R[4], R[7], R[0]); - if (R[15]==0x2328CC8) - printf("SUM=%08X %08X %08X\n", R[4], R[7], R[0]); - if (R[15]>=0x2328D6C && R[15]<=0x2328D9C) - printf("%08X CALC %08X %08X\n", R[15]-4, R[0], R[1]); - if (R[15]>=0x232CCCC && R[15]<=0x232CED4) - printf("%08X DIV %08X %08X %08X %08X carry %d\n", R[15]-4, R[0], R[1], R[2], R[3], (CPSR&0x20000000)?1:0);*/ - // temp. debug cruft addr = R[15] - (CPSR&0x20 ? 4:8); cpsr = CPSR; @@ -19,6 +19,7 @@ #include <stdio.h> #include "NDS.h" #include "DMA.h" +#include "NDSCart.h" // NOTES ON DMA SHIT @@ -82,7 +83,7 @@ void DMA::WriteCnt(u32 val) if (CPU == 0) StartMode = (Cnt >> 27) & 0x7; else - StartMode = ((Cnt >> 28) & 0x3) | 0x8; + StartMode = ((Cnt >> 28) & 0x3) | 0x10; if ((StartMode & 0x7) == 0) Start(); @@ -106,6 +107,19 @@ void DMA::Start() if ((Cnt & 0x00060000) == 0x00060000) CurDstAddr = DstAddr; + // special path for cart DMA. this is a gross hack. + // emulating it properly requires emulating cart transfer delays, so uh... TODO + if (CurSrcAddr==0x04100010 && RemCount==1 && (Cnt & 0x07E00000)==0x07000000 && + ((CPU==0 && StartMode==0x06) || (CPU==1 && StartMode==0x12))) + { + printf("CART DMA %08X\n", CurDstAddr); + NDSCart::DMA(CurDstAddr); + Cnt &= ~0x80000000; + if (Cnt & 0x40000000) + NDS::TriggerIRQ(CPU, NDS::IRQ_DMA0 + Num); + return; + } + //printf("ARM%d DMA%d %08X %08X->%08X %d bytes %dbit\n", CPU?7:9, Num, Cnt, CurSrcAddr, CurDstAddr, RemCount*((Cnt&0x04000000)?4:2), (Cnt&0x04000000)?32:16); // TODO: NOT MAKE THE DMA INSTANT!! @@ -113,7 +113,7 @@ void GPU2D::Write16(u32 addr, u16 val) case 0x01E: BGYPos[3] = val; return; } - printf("unknown GPU write16 %08X %04X\n", addr, val); + //printf("unknown GPU write16 %08X %04X\n", addr, val); } void GPU2D::Write32(u32 addr, u32 val) @@ -21,6 +21,7 @@ #include "NDS.h" #include "ARM.h" #include "CP15.h" +#include "NDSCart.h" #include "DMA.h" #include "FIFO.h" #include "GPU.h" @@ -28,12 +29,6 @@ #include "RTC.h" #include "Wifi.h" -// derp -namespace SPI_Firmware -{ - extern u8* Firmware; -} - namespace NDS { @@ -74,6 +69,11 @@ u32 ARM9ITCMSize; u8 ARM9DTCM[0x4000]; u32 ARM9DTCMBase, ARM9DTCMSize; +u16 ExMemCnt[2]; + +u8 ROMSeed0[2*8]; +u8 ROMSeed1[2*8]; + // IO shit u32 IME[2]; u32 IE[2], IF[2]; @@ -99,12 +99,6 @@ u32 DivDenominator[2]; u32 DivQuotient[2]; u32 DivRemainder[2]; -u32 ROMSPIControl; -u32 ROMControl; -u8 ROMCommand[8]; -u8 ROMCurCommand[8]; -u32 ROMReadPos, ROMReadSize; - u32 KeyInput; u16 _soundbias; // temp @@ -129,6 +123,7 @@ void Init() IPCFIFO9 = new FIFO(16); IPCFIFO7 = new FIFO(16); + NDSCart::Init(); GPU::Init(); SPI::Init(); RTC::Init(); @@ -220,6 +215,11 @@ void Reset() ARM9DTCMBase = 0xFFFFFFFF; ARM9DTCMSize = 0; + ExMemCnt[0] = 0; + ExMemCnt[1] = 0; + memset(ROMSeed0, 0, 2*8); + memset(ROMSeed1, 0, 2*8); + IME[0] = 0; IME[1] = 0; @@ -237,10 +237,6 @@ void Reset() DivCnt = 0; - ROMSPIControl = 0; - ROMControl = 0; - memset(ROMCommand, 0, 8); - ARM9->Reset(); ARM7->Reset(); CP15::Reset(); @@ -250,6 +246,7 @@ void Reset() for (i = 0; i < 8; i++) DMAs[i]->Reset(); memset(DMA9Fill, 0, 4*4); + NDSCart::Reset(); GPU::Reset(); SPI::Reset(); RTC::Reset(); @@ -269,6 +266,7 @@ void Reset() // test //LoadROM(); //LoadFirmware(); + NDSCart::LoadROM("rom/nsmb.nds"); Running = true; // hax } @@ -512,6 +510,17 @@ bool HaltInterrupted(u32 cpu) +void CheckDMAs(u32 cpu, u32 mode) +{ + cpu <<= 2; + DMAs[cpu+0]->StartIfNeeded(mode); + DMAs[cpu+1]->StartIfNeeded(mode); + DMAs[cpu+2]->StartIfNeeded(mode); + DMAs[cpu+3]->StartIfNeeded(mode); +} + + + const s32 TimerPrescaler[4] = {2, 128, 512, 2048}; void TimerIncrement(u32 param) @@ -579,78 +588,6 @@ void TimerStart(u32 id, u16 cnt) -void ROMEndTransfer(u32 cpu) -{ - ROMControl &= ~(1<<23); - ROMControl &= ~(1<<31); - - if (ROMSPIControl & (1<<14)) - TriggerIRQ(cpu, IRQ_CartSendDone); -} - -void ROMStartTransfer(u32 cpu) -{ - u32 datasize = (ROMControl >> 24) & 0x7; - if (datasize == 7) - datasize = 4; - else if (datasize > 0) - datasize = 0x100 << datasize; - - //datasize += (ROMControl & 0x1FFF); // KEY1 gap - - ROMReadPos = 0; - ROMReadSize = datasize; - - *(u32*)&ROMCurCommand[0] = *(u32*)&ROMCommand[0]; - *(u32*)&ROMCurCommand[4] = *(u32*)&ROMCommand[4]; - - printf("ROM COMMAND %04X %08X %02X%02X%02X%02X%02X%02X%02X%02X SIZE %04X\n", - ROMSPIControl, ROMControl, - ROMCommand[0], ROMCommand[1], ROMCommand[2], ROMCommand[3], - ROMCommand[4], ROMCommand[5], ROMCommand[6], ROMCommand[7], - datasize); - - ROMControl |= (1<<23); - - if (datasize == 0) - { - // hax - /*if (ROMCommand[0] == 0xBA) - ScheduleEvent(0x910*5*2, ROMEndTransfer, cpu); - else*/ - ROMEndTransfer(cpu); - printf("ROM transfer done. %08X %08X\n", ARM7Read32(0x03FFFFF8), ARM7Read32(0x03FFFFFC)); - } -} - -u32 ROMReadData(u32 cpu) -{ - u32 ret = 0; - - switch (ROMCurCommand[0]) - { - case 0x9F: ret = 0xFFFFFFFF; break; - - case 0x00: - // TODO: feed an actual cart header! - ret = 0; - break; - - case 0x90: - // chip ID - ret = 0; - break; - } - - ROMReadPos += 4; - if (ROMReadPos >= ROMReadSize) - ROMEndTransfer(cpu); - - return ret; -} - - - void StartDiv() { // TODO: division isn't instant! @@ -1398,8 +1335,9 @@ u16 ARM9IORead16(u32 addr) return val; } - case 0x04000204: return 0;//0xFFFF; + case 0x040001A0: return NDSCart::SPICnt; + case 0x04000204: return ExMemCnt[0]; case 0x04000208: return IME[0]; case 0x04000280: return DivCnt; @@ -1450,6 +1388,8 @@ u32 ARM9IORead32(u32 addr) case 0x04000108: return Timers[2].Counter | (Timers[2].Control << 16); case 0x0400010C: return Timers[3].Counter | (Timers[3].Control << 16); + case 0x040001A4: return NDSCart::ROMCnt; + case 0x04000208: return IME[0]; case 0x04000210: return IE[0]; case 0x04000214: return IF[0]; @@ -1483,6 +1423,10 @@ u32 ARM9IORead32(u32 addr) } else return IPCFIFO7->Peek(); + + case 0x04100010: + if (!(ExMemCnt[0] & (1<<11))) return NDSCart::ReadData(); + return 0; } if (addr >= 0x04000000 && addr < 0x04000060) @@ -1503,14 +1447,29 @@ void ARM9IOWrite8(u32 addr, u8 val) switch (addr) { case 0x040001A0: - ROMSPIControl &= 0xFF00; - ROMSPIControl |= val; + if (!(ExMemCnt[0] & (1<<11))) + { + NDSCart::SPICnt &= 0xFF00; + NDSCart::SPICnt |= val; + } return; case 0x040001A1: - ROMSPIControl &= 0x00FF; - ROMSPIControl |= (val << 8); + if (!(ExMemCnt[0] & (1<<11))) + { + NDSCart::SPICnt &= 0x00FF; + NDSCart::SPICnt |= (val << 8); + } return; + case 0x040001A8: NDSCart::ROMCommand[0] = val; return; + case 0x040001A9: NDSCart::ROMCommand[1] = val; return; + case 0x040001AA: NDSCart::ROMCommand[2] = val; return; + case 0x040001AB: NDSCart::ROMCommand[3] = val; return; + case 0x040001AC: NDSCart::ROMCommand[4] = val; return; + case 0x040001AD: NDSCart::ROMCommand[5] = val; return; + case 0x040001AE: NDSCart::ROMCommand[6] = val; return; + case 0x040001AF: NDSCart::ROMCommand[7] = val; return; + case 0x04000208: IME[0] = val & 0x1; return; case 0x04000240: GPU::MapVRAM_AB(0, val); return; @@ -1584,7 +1543,15 @@ void ARM9IOWrite16(u32 addr, u16 val) return; case 0x040001A0: - ROMSPIControl = val; + if (!(ExMemCnt[0] & (1<<11))) NDSCart::SPICnt = val; + return; + + case 0x040001B8: ROMSeed0[4] = val & 0x7F; return; + case 0x040001BA: ROMSeed1[4] = val & 0x7F; return; + + case 0x04000204: + ExMemCnt[0] = val; + ExMemCnt[1] = (ExMemCnt[1] & 0x007F) | (val & 0xFF80); return; case 0x04000208: IME[0] = val & 0x1; return; @@ -1689,15 +1656,19 @@ void ARM9IOWrite32(u32 addr, u32 val) return; case 0x040001A0: - ROMSPIControl = val & 0xFFFF; - // TODO: SPI shit + if (!(ExMemCnt[0] & (1<<11))) + { + NDSCart::SPICnt = val & 0xFFFF; + // TODO: SPI shit + } return; case 0x040001A4: - val &= ~0x00800000; - ROMControl = val; - if (val & 0x80000000) ROMStartTransfer(0); + if (!(ExMemCnt[0] & (1<<11))) NDSCart::WriteCnt(val); return; + case 0x040001B0: *(u32*)&ROMSeed0[0] = val; return; + case 0x040001B4: *(u32*)&ROMSeed1[0] = val; return; + case 0x04000208: IME[0] = val & 0x1; return; case 0x04000210: IE[0] = val; if (val&~0x000F0F7D)printf("unusual IRQ %08X\n",val);return; case 0x04000214: IF[0] &= ~val; return; @@ -1754,10 +1725,6 @@ u8 ARM7IORead8(u32 addr) case 0x04000241: return WRAMCnt; case 0x04000300: return PostFlag7; - - //case 0x04000403: - //Halt(); - //return 0; } if (addr >= 0x04000400 && addr < 0x04000520) @@ -1803,9 +1770,12 @@ u16 ARM7IORead16(u32 addr) return val; } + case 0x040001A0: return NDSCart::SPICnt; + case 0x040001C0: return SPI::ReadCnt(); case 0x040001C2: return SPI::ReadData(); + case 0x04000204: return ExMemCnt[1]; case 0x04000208: return IME[1]; case 0x04000300: return PostFlag7; @@ -1848,8 +1818,7 @@ u32 ARM7IORead32(u32 addr) case 0x04000108: return Timers[6].Counter | (Timers[6].Control << 16); case 0x0400010C: return Timers[7].Counter | (Timers[7].Control << 16); - case 0x040001A4: - return ROMControl; + case 0x040001A4: return NDSCart::ROMCnt; case 0x040001C0: return SPI::ReadCnt() | (SPI::ReadData() << 16); @@ -1879,7 +1848,9 @@ u32 ARM7IORead32(u32 addr) else return IPCFIFO9->Peek(); - case 0x04100010: return ROMReadData(1); + case 0x04100010: + if (ExMemCnt[0] & (1<<11)) return NDSCart::ReadData(); + return 0; } if (addr >= 0x04000400 && addr < 0x04000520) @@ -1899,22 +1870,28 @@ void ARM7IOWrite8(u32 addr, u8 val) case 0x04000138: RTC::Write(val, true); return; case 0x040001A0: - ROMSPIControl &= 0xFF00; - ROMSPIControl |= val; + if (ExMemCnt[0] & (1<<11)) + { + NDSCart::SPICnt &= 0xFF00; + NDSCart::SPICnt |= val; + } return; case 0x040001A1: - ROMSPIControl &= 0x00FF; - ROMSPIControl |= (val << 8); + if (ExMemCnt[0] & (1<<11)) + { + NDSCart::SPICnt &= 0x00FF; + NDSCart::SPICnt |= (val << 8); + } return; - case 0x040001A8: ROMCommand[0] = val; return; - case 0x040001A9: ROMCommand[1] = val; return; - case 0x040001AA: ROMCommand[2] = val; return; - case 0x040001AB: ROMCommand[3] = val; return; - case 0x040001AC: ROMCommand[4] = val; return; - case 0x040001AD: ROMCommand[5] = val; return; - case 0x040001AE: ROMCommand[6] = val; return; - case 0x040001AF: ROMCommand[7] = val; return; + case 0x040001A8: NDSCart::ROMCommand[0] = val; return; + case 0x040001A9: NDSCart::ROMCommand[1] = val; return; + case 0x040001AA: NDSCart::ROMCommand[2] = val; return; + case 0x040001AB: NDSCart::ROMCommand[3] = val; return; + case 0x040001AC: NDSCart::ROMCommand[4] = val; return; + case 0x040001AD: NDSCart::ROMCommand[5] = val; return; + case 0x040001AE: NDSCart::ROMCommand[6] = val; return; + case 0x040001AF: NDSCart::ROMCommand[7] = val; return; case 0x040001C2: SPI::WriteData(val); @@ -1986,9 +1963,13 @@ void ARM7IOWrite16(u32 addr, u16 val) return; case 0x040001A0: - ROMSPIControl = val; + if (ExMemCnt[0] & (1<<11)) + NDSCart::SPICnt = val; return; + case 0x040001B8: ROMSeed0[12] = val & 0x7F; return; + case 0x040001BA: ROMSeed1[12] = val & 0x7F; return; + case 0x040001C0: SPI::WriteCnt(val); return; @@ -1997,6 +1978,10 @@ void ARM7IOWrite16(u32 addr, u16 val) SPI::WriteData(val & 0xFF); return; + case 0x04000204: + ExMemCnt[1] = (ExMemCnt[1] & 0xFF80) | (val & 0x007F); + return; + case 0x04000208: IME[1] = val & 0x1; return; case 0x04000300: @@ -2008,7 +1993,7 @@ void ARM7IOWrite16(u32 addr, u16 val) case 0x04000304: PowerControl7 = val; return; - case 0x04000504: + case 0x04000504: // removeme _soundbias = val & 0x3FF; return; } @@ -2072,15 +2057,19 @@ void ARM7IOWrite32(u32 addr, u32 val) return; case 0x040001A0: - ROMSPIControl = val & 0xFFFF; - // TODO: SPI shit + if (ExMemCnt[0] & (1<<11)) + { + NDSCart::SPICnt = val & 0xFFFF; + // TODO: SPI shit + } return; case 0x040001A4: - val &= ~0x00800000; - ROMControl = val; - if (val & 0x80000000) ROMStartTransfer(1); + if (ExMemCnt[0] & (1<<11)) NDSCart::WriteCnt(val); return; + case 0x040001B0: *(u32*)&ROMSeed0[8] = val; return; + case 0x040001B4: *(u32*)&ROMSeed1[8] = val; return; + case 0x04000208: IME[1] = val & 0x1; return; case 0x04000210: IE[1] = val; return; case 0x04000214: IF[1] &= ~val; return; @@ -80,6 +80,13 @@ extern u32 IE[2]; extern u32 IF[2]; extern Timer Timers[8]; +extern u16 ExMemCnt[2]; +extern u8 ROMSeed0[2*8]; +extern u8 ROMSeed1[2*8]; + +extern u8 ARM9BIOS[0x1000]; +extern u8 ARM7BIOS[0x4000]; + extern u32 ARM9ITCMSize; extern u32 ARM9DTCMBase, ARM9DTCMSize; @@ -105,6 +112,8 @@ void MapSharedWRAM(u8 val); void TriggerIRQ(u32 cpu, u32 irq); bool HaltInterrupted(u32 cpu); +void CheckDMAs(u32 cpu, u32 mode); + u8 ARM9Read8(u32 addr); u16 ARM9Read16(u32 addr); u32 ARM9Read32(u32 addr); diff --git a/NDSCart.cpp b/NDSCart.cpp new file mode 100644 index 0000000..5334c15 --- /dev/null +++ b/NDSCart.cpp @@ -0,0 +1,438 @@ +/* + 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 <string.h> +#include "NDS.h" +#include "NDSCart.h" + +namespace NDSCart +{ + +u16 SPICnt; +u32 ROMCnt; + +u8 ROMCommand[8]; +u32 ROMDataOut; + +u8 DataOut[0x4000]; +u32 DataOutPos; +u32 DataOutLen; + +bool CartInserted; +u8* CartROM; +u32 CartROMSize; +u32 CartID; + +u32 CmdEncMode; +u32 DataEncMode; + +u32 Key1_KeyBuf[0x412]; + +u64 Key2_X; +u64 Key2_Y; + + +u32 ByteSwap(u32 val) +{ + return (val >> 24) | ((val >> 8) & 0xFF00) | ((val << 8) & 0xFF0000) | (val << 24); +} + +void Key1_Encrypt(u32* data) +{ + u32 y = data[0]; + u32 x = data[1]; + u32 z; + + for (u32 i = 0x0; i <= 0xF; i++) + { + z = Key1_KeyBuf[i] ^ x; + x = Key1_KeyBuf[0x012 + (z >> 24) ]; + x += Key1_KeyBuf[0x112 + ((z >> 16) & 0xFF)]; + x ^= Key1_KeyBuf[0x212 + ((z >> 8) & 0xFF)]; + x += Key1_KeyBuf[0x312 + (z & 0xFF)]; + x ^= y; + y = z; + } + + data[0] = x ^ Key1_KeyBuf[0x10]; + data[1] = y ^ Key1_KeyBuf[0x11]; +} + +void Key1_Decrypt(u32* data) +{ + u32 y = data[0]; + u32 x = data[1]; + u32 z; + + for (u32 i = 0x11; i >= 0x2; i--) + { + z = Key1_KeyBuf[i] ^ x; + x = Key1_KeyBuf[0x012 + (z >> 24) ]; + x += Key1_KeyBuf[0x112 + ((z >> 16) & 0xFF)]; + x ^= Key1_KeyBuf[0x212 + ((z >> 8) & 0xFF)]; + x += Key1_KeyBuf[0x312 + (z & 0xFF)]; + x ^= y; + y = z; + } + + data[0] = x ^ Key1_KeyBuf[0x1]; + data[1] = y ^ Key1_KeyBuf[0x0]; +} + +void Key1_ApplyKeycode(u32* keycode, u32 mod) +{ + Key1_Encrypt(&keycode[1]); + Key1_Encrypt(&keycode[0]); + + u32 temp[2] = {0,0}; + + for (u32 i = 0; i <= 0x11; i++) + { + Key1_KeyBuf[i] ^= ByteSwap(keycode[i % mod]); + } + for (u32 i = 0; i <= 0x410; i+=2) + { + Key1_Encrypt(temp); + Key1_KeyBuf[i ] = temp[1]; + Key1_KeyBuf[i+1] = temp[0]; + } +} + +void Key1_InitKeycode(u32 idcode, u32 level, u32 mod) +{ + memcpy(Key1_KeyBuf, &NDS::ARM7BIOS[0x30], 0x1048); // hax + + u32 keycode[3] = {idcode, idcode>>1, idcode<<1}; + if (level >= 1) Key1_ApplyKeycode(keycode, mod); + if (level >= 2) Key1_ApplyKeycode(keycode, mod); + if (level >= 3) + { + keycode[1] <<= 1; + keycode[2] >>= 1; + Key1_ApplyKeycode(keycode, mod); + } +} + + +void Key2_Encrypt(u8* data, u32 len) +{ + for (u32 i = 0; i < len; i++) + { + Key2_X = (((Key2_X >> 5) ^ + (Key2_X >> 17) ^ + (Key2_X >> 18) ^ + (Key2_X >> 31)) & 0xFF) + + (Key2_X << 8); + Key2_Y = (((Key2_Y >> 5) ^ + (Key2_Y >> 23) ^ + (Key2_Y >> 18) ^ + (Key2_Y >> 31)) & 0xFF) + + (Key2_Y << 8); + + Key2_X &= 0x0000007FFFFFFFFFULL; + Key2_Y &= 0x0000007FFFFFFFFFULL; + } +} + + +void Init() +{ +} + +void Reset() +{ + SPICnt = 0; + ROMCnt = 0; + + memset(ROMCommand, 0, 8); + ROMDataOut = 0; + + Key2_X = 0; + Key2_Y = 0; + + memset(DataOut, 0, 0x4000); + DataOutPos = 0; + DataOutLen = 0; + + CartInserted = false; + CartROM = NULL; + CartROMSize = 0; + CartID = 0; + + CmdEncMode = 0; + DataEncMode = 0; +} + + +void LoadROM(char* path) +{ + // TODO: streaming mode? for really big ROMs or systems with limited RAM + // for now we're lazy + + FILE* f = fopen(path, "rb"); + + fseek(f, 0, SEEK_END); + u32 len = (u32)ftell(f); + + CartROMSize = 0x200; + while (CartROMSize < len) + CartROMSize <<= 1; + + u32 gamecode; + fseek(f, 0x0C, SEEK_SET); + fread(&gamecode, 4, 1, f); + + CartROM = new u8[CartROMSize]; + memset(CartROM, 0, CartROMSize); + fseek(f, 0, SEEK_SET); + fread(CartROM, 1, len, f); + + fclose(f); + //CartROM = f; + + CartInserted = true; + + // generate a ROM ID + // note: most games don't check the actual value + // it just has to stay the same throughout gameplay + CartID = 0x00001FC2; + + // encryption + Key1_InitKeycode(gamecode, 2, 2); +} + +void ReadROM(u32 addr, u32 len, u32 offset) +{ + if (!CartInserted) return; + + if (addr >= CartROMSize) return; + if ((addr+len) > CartROMSize) + len = CartROMSize - addr; + + memcpy(DataOut+offset, CartROM+addr, len); +} + +void ReadROM_B7(u32 addr, u32 len, u32 offset) +{ + addr &= (CartROMSize-1); + if (addr < 0x8000) addr = 0x8000 + (addr & 0x1FF); + + memcpy(DataOut+offset, CartROM+addr, len); +} + + +void EndTransfer() +{ + ROMCnt &= ~(1<<23); + ROMCnt &= ~(1<<31); + + if (SPICnt & (1<<14)) + NDS::TriggerIRQ((NDS::ExMemCnt[0]>>11)&0x1, NDS::IRQ_CartSendDone); +} + +void ROMPrepareData(u32 param) +{ + if (DataOutPos >= DataOutLen) + ROMDataOut = 0; + else + ROMDataOut = *(u32*)&DataOut[DataOutPos]; + + DataOutPos += 4; + + ROMCnt |= (1<<23); + NDS::CheckDMAs(0, 0x06); + NDS::CheckDMAs(1, 0x12); + + if (DataOutPos < DataOutLen) + NDS::ScheduleEvent((ROMCnt & (1<<27)) ? 8:5, ROMPrepareData, 0); +} + +void WriteCnt(u32 val) +{ + ROMCnt = val & 0xFF7F7FFF; + + if (!(SPICnt & (1<<15))) return; + + if (val & (1<<15)) + { + u32 snum = (NDS::ExMemCnt[0]>>8)&0x8; + u64 seed0 = *(u32*)&NDS::ROMSeed0[snum] | ((u64)NDS::ROMSeed0[snum+4] << 32); + u64 seed1 = *(u32*)&NDS::ROMSeed1[snum] | ((u64)NDS::ROMSeed1[snum+4] << 32); + + Key2_X = 0; + Key2_Y = 0; + for (u32 i = 0; i < 39; i++) + { + if (seed0 & (1ULL << i)) Key2_X |= (1ULL << (38-i)); + if (seed1 & (1ULL << i)) Key2_Y |= (1ULL << (38-i)); + } + + printf("seed0: %02X%08X\n", (u32)(seed0>>32), (u32)seed0); + printf("seed1: %02X%08X\n", (u32)(seed1>>32), (u32)seed1); + printf("key2 X: %02X%08X\n", (u32)(Key2_X>>32), (u32)Key2_X); + printf("key2 Y: %02X%08X\n", (u32)(Key2_Y>>32), (u32)Key2_Y); + } + + if (!(ROMCnt & (1<<31))) return; + + u32 datasize = (ROMCnt >> 24) & 0x7; + if (datasize == 7) + datasize = 4; + else if (datasize > 0) + datasize = 0x100 << datasize; + + DataOutPos = 0; + DataOutLen = datasize; + + // handle KEY1 encryption as needed. + // KEY2 encryption is implemented in hardware and doesn't need to be handled. + u8 cmd[8]; + if (CmdEncMode == 1) + { + *(u32*)&cmd[0] = ByteSwap(*(u32*)&ROMCommand[4]); + *(u32*)&cmd[4] = ByteSwap(*(u32*)&ROMCommand[0]); + Key1_Decrypt((u32*)cmd); + u32 tmp = ByteSwap(*(u32*)&cmd[4]); + *(u32*)&cmd[4] = ByteSwap(*(u32*)&cmd[0]); + *(u32*)&cmd[0] = tmp; + } + else + { + *(u32*)&cmd[0] = *(u32*)&ROMCommand[0]; + *(u32*)&cmd[4] = *(u32*)&ROMCommand[4]; + } + + printf("ROM COMMAND %04X %08X %02X%02X%02X%02X%02X%02X%02X%02X SIZE %04X\n", + SPICnt, ROMCnt, + cmd[0], cmd[1], cmd[2], cmd[3], + cmd[4], cmd[5], cmd[6], cmd[7], + datasize); + + switch (cmd[0]) + { + case 0x9F: + memset(DataOut, 0xFF, DataOutLen); + break; + + case 0x00: + memset(DataOut, 0, DataOutLen); + if (DataOutLen > 0x1000) + { + ReadROM(0, 0x1000, 0); + for (u32 pos = 0x1000; pos < DataOutLen; pos += 0x1000) + memcpy(DataOut+pos, DataOut, 0x1000); + } + else + ReadROM(0, DataOutLen, 0); + break; + + case 0x90: + case 0xB8: + for (u32 pos = 0; pos < DataOutLen; pos += 4) + *(u32*)&DataOut[pos] = CartID; + break; + + case 0x3C: + CmdEncMode = 1; + break; + + case 0xB7: + { + u32 addr = (cmd[1]<<24) | (cmd[2]<<16) | (cmd[3]<<8) | cmd[4]; + memset(DataOut, 0, DataOutLen); + + if (((addr + DataOutLen - 1) >> 12) != (addr >> 12)) + { + u32 len1 = 0x1000 - (addr & 0xFFF); + ReadROM_B7(addr, len1, 0); + ReadROM_B7(addr+len1, DataOutLen-len1, len1); + } + else + ReadROM_B7(addr, DataOutLen, 0); + } + break; + + default: + switch (cmd[0] & 0xF0) + { + case 0x40: + DataEncMode = 2; + break; + + case 0x10: + for (u32 pos = 0; pos < DataOutLen; pos += 4) + *(u32*)&DataOut[pos] = CartID; + break; + + case 0xA0: + CmdEncMode = 2; + break; + } + break; + } + + //ROMCnt &= ~(1<<23); + ROMCnt |= (1<<23); + + if (datasize == 0) + EndTransfer(); + else + { + NDS::CheckDMAs(0, 0x06); + NDS::CheckDMAs(1, 0x12); + } + //NDS::ScheduleEvent((ROMCnt & (1<<27)) ? 8:5, ROMPrepareData, 0); +} + +u32 ReadData() +{ + /*if (ROMCnt & (1<<23)) + { + ROMCnt &= ~(1<<23); + if (DataOutPos >= DataOutLen) + EndTransfer(); + } + + return ROMDataOut;*/ + u32 ret; + if (DataOutPos >= DataOutLen) + ret = 0; + else + ret = *(u32*)&DataOut[DataOutPos]; + + DataOutPos += 4; + + if (DataOutPos == DataOutLen) + EndTransfer(); + + return ret; +} + +void DMA(u32 addr) +{ + void (*writefn)(u32,u32) = (NDS::ExMemCnt[0] & (1<<11)) ? NDS::ARM7Write32 : NDS::ARM9Write32; + for (u32 i = 0; i < DataOutLen; i+=4) + { + writefn(addr+i, *(u32*)&DataOut[i]); + } + + EndTransfer(); +} + +} diff --git a/NDSCart.h b/NDSCart.h new file mode 100644 index 0000000..8396aca --- /dev/null +++ b/NDSCart.h @@ -0,0 +1,47 @@ +/* + 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/. +*/ + +#ifndef NDSCART_H +#define NDSCART_H + +#include "types.h" + +namespace NDSCart +{ + +extern u16 SPICnt; +extern u32 ROMCnt; + +extern u8 ROMCommand[8]; +extern u32 ROMDataOut; + +extern u8 EncSeed0[5]; +extern u8 EncSeed1[5]; + +void Init(); +void Reset(); + +void LoadROM(char* path); + +void WriteCnt(u32 val); +u32 ReadData(); +void DMA(u32 addr); + +} + +#endif @@ -90,7 +90,7 @@ void ByteIn(u8 val) case 0x20: // TODO: get actual system time - Output[0] = 0x16; + Output[0] = 0x17; Output[1] = 0x01; Output[2] = 0x19; Output[3] = 0x03; // day of week. checkme diff --git a/melonDS.depend b/melonDS.depend index b32f606..1d52f3c 100644 --- a/melonDS.depend +++ b/melonDS.depend @@ -5,17 +5,18 @@ "NDS.h" "GPU.h" -1484752883 c:\documents\sources\melonds\nds.h +1485110344 c:\documents\sources\melonds\nds.h "types.h" 1481161027 c:\documents\sources\melonds\types.h -1484922190 source:c:\documents\sources\melonds\nds.cpp +1485111787 source:c:\documents\sources\melonds\nds.cpp <stdio.h> <string.h> "NDS.h" "ARM.h" "CP15.h" + "NDSCart.h" "DMA.h" "FIFO.h" "GPU.h" @@ -23,7 +24,7 @@ "RTC.h" "Wifi.h" -1484917677 source:c:\documents\sources\melonds\arm.cpp +1485106814 source:c:\documents\sources\melonds\arm.cpp <stdio.h> "NDS.h" "ARM.h" @@ -83,7 +84,7 @@ "NDS.h" "SPI.h" -1485012361 source:c:\documents\sources\melonds\gpu2d.cpp +1485016053 source:c:\documents\sources\melonds\gpu2d.cpp <stdio.h> <string.h> "NDS.h" @@ -105,10 +106,11 @@ 1484612398 c:\documents\sources\melonds\fifo.h "types.h" -1484871851 source:c:\documents\sources\melonds\dma.cpp +1485113211 source:c:\documents\sources\melonds\dma.cpp <stdio.h> "NDS.h" "DMA.h" + "NDSCart.h" 1484698068 c:\documents\sources\melonds\dma.h "types.h" @@ -125,8 +127,17 @@ 1484848282 c:\documents\sources\melonds\rtc.h "types.h" -1484922235 source:c:\documents\sources\melonds\rtc.cpp +1485016019 source:c:\documents\sources\melonds\rtc.cpp <stdio.h> <string.h> "RTC.h" +1485112531 c:\documents\sources\melonds\ndscart.h + "types.h" + +1485112522 source:c:\documents\sources\melonds\ndscart.cpp + <stdio.h> + <string.h> + "NDS.h" + "NDSCart.h" + |