From 28435d93346c8dcfbed5f6ce07cf8a496d6276a7 Mon Sep 17 00:00:00 2001 From: zeromus Date: Wed, 15 Jul 2009 19:42:32 +0000 Subject: [PATCH] totally rewrite main emulation loop! YOUR SAVESTATES ARE INVALIDATED. your timing is all different. but, your timing is more precise, a few hidden old bugs surfaced and were smashed, and some games work that didn't used to. INSTRUCTIONS_PER_BATCH is a thing of the past. crazymax and luigi, I may have broken your parts, but hopefully only a little bit. your new hookups into the emulation loop are more complicated but potentially faster and definitely more precise. --- desmume/ChangeLog | 14 +- desmume/src/FIFO.cpp | 18 +- desmume/src/MMU.cpp | 626 ++----- desmume/src/MMU.h | 28 +- desmume/src/NDSSystem.cpp | 2123 +++++++++++------------ desmume/src/NDSSystem.h | 14 +- desmume/src/armcpu.cpp | 2 +- desmume/src/armcpu.h | 2 + desmume/src/common.cpp | 2 +- desmume/src/gfx3d.cpp | 6 +- desmume/src/readwrite.cpp | 10 + desmume/src/readwrite.h | 2 + desmume/src/saves.cpp | 24 +- desmume/src/types.h | 2 +- desmume/src/windows/DeSmuME_2005.vcproj | 28 +- desmume/src/windows/main.cpp | 4 +- 16 files changed, 1272 insertions(+), 1633 deletions(-) diff --git a/desmume/ChangeLog b/desmume/ChangeLog index 01fb32645..2c29a8416 100644 --- a/desmume/ChangeLog +++ b/desmume/ChangeLog @@ -1,21 +1,31 @@ 0.9.4 -> ??? (r2437-r???) +??? introduces an entirely rewritten main emulation loop. +This totally changes the timing, and totally breaks old savestates. + Highlights: * win32: lua engine, path configuration, 7z dearchiving support + * rewritten main emulation loop General/Core: bug: fix cflash directory support for non-windows bug: fix freeze in cart irq bug: correctly emulate dma to/from tcm + enh: add guitar grip emulation + enh: add more powerful antigrain-based drawing library and rewrite OSD system enh: ideas-style debugging prints Graphics: bug: fixing of obj blending and bmp obj rendering + bug: fix backdrop blending with garbage + bug: fix 256B granularity sprite addressing for sub gpu bug: swrast: add clear image emulation bug: swrast: add edge marking - + Windows: - bug: improve map view tool + bug: improve map view tool to support more modes + enh: added 2x resizing filters (hq2x, 2xsai, supereagle, scanlines) + enh: soundview can now mute channels Linux: enh: alsa microphone support diff --git a/desmume/src/FIFO.cpp b/desmume/src/FIFO.cpp index 979b0d873..1dbfbe690 100644 --- a/desmume/src/FIFO.cpp +++ b/desmume/src/FIFO.cpp @@ -28,6 +28,7 @@ #include "debug.h" #include "mem.h" #include "MMU.h" +#include "NDSSystem.h" // ========================================================= IPC FIFO IPC_FIFO ipc_fifo[2]; // 0 - ARM9 @@ -174,6 +175,8 @@ void GFX_FIFOsend(u8 cmd, u32 param) #endif T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x600, gxstat); + + NDS_RescheduleGXFIFO(); } BOOL GFX_FIFOrecv(u8 *cmd, u32 *param) @@ -183,6 +186,7 @@ BOOL GFX_FIFOrecv(u8 *cmd, u32 *param) if (gxstat & 0xC0000000) { setIF(0, (1<<21)); + //NDS_makeARM9Int(21); } #endif if (gxFIFO.tail == 0) // empty @@ -193,18 +197,23 @@ BOOL GFX_FIFOrecv(u8 *cmd, u32 *param) if ((gxstat & 0x80000000)) // empty { setIF(0, (1<<21)); + //NDS_makeARM9Int(21); } return FALSE; } if (gxstat & 0x40000000) // IRQ: less half { - if (gxstat & 0x02000000) setIF(0, (1<<21)); + if (gxstat & 0x02000000) + setIF(0, (1<<21)); + //NDS_makeARM9Int(21); } if ((gxstat & 0x80000000)) // IRQ: empty { - if (gxstat & 0x04000000) setIF(0, (1<<21)); + if (gxstat & 0x04000000) + setIF(0, (1<<21)); + //NDS_makeARM9Int(21); } gxstat &= 0xF000FFFF; @@ -228,6 +237,8 @@ BOOL GFX_FIFOrecv(u8 *cmd, u32 *param) T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x600, gxstat); + NDS_RescheduleGXFIFO(); + return TRUE; } @@ -241,10 +252,13 @@ void GFX_FIFOcnt(u32 val) return; } T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x600, gxstat); + + NDS_RescheduleGXFIFO(); /*if (gxstat & 0xC0000000) { setIF(0, (1<<21)); + //NDS_makeARM9Int(21); }*/ } diff --git a/desmume/src/MMU.cpp b/desmume/src/MMU.cpp index 348329daa..cf1f325b3 100644 --- a/desmume/src/MMU.cpp +++ b/desmume/src/MMU.cpp @@ -410,23 +410,8 @@ u8 *MMU_RenderMapToLCD(u32 vram_addr) } -template -void DMAtoVRAMmapping() -{ - //THIS IS ALSO DANGEROUS!!!!!! - //but i dont think it needs to be done - - /*u32 dst = DMADst[ARMCPU_ARM9][DMA_CHANNEL]; - - bool unmapped; - dst = MMU_LCDmap(dst,unmapped); - - DMADst[ARMCPU_ARM9][DMA_CHANNEL] = dst;*/ -} - #define LOG_VRAM_ERROR() LOG("No data for block %i MST %i\n", block, VRAMBankCnt & 0x07); - struct VramConfiguration { enum Purpose { @@ -983,7 +968,7 @@ void MMU_clearMem() memset(MMU.reg_IF, 0, sizeof(u32) * 2); memset(MMU.DMAStartTime, 0, sizeof(u32) * 2 * 4); - memset(MMU.DMACycle, 0, sizeof(s32) * 2 * 4); + memset(MMU.DMACycle, 0, sizeof(MMU.DMACycle)); memset(MMU.DMACrt, 0, sizeof(u32) * 2 * 4); memset(MMU.DMAing, 0, sizeof(BOOL) * 2 * 4); @@ -1011,9 +996,7 @@ void MMU_clearMem() partie = 1; addonsReset(); Mic_Reset(); -#ifdef USE_GEOMETRY_FIFO_EMULATION MMU.gfx3dCycles = 0; -#endif } void MMU_setRom(u8 * rom, u32 mask) @@ -1062,10 +1045,11 @@ static void execsqrt() { T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2B4, 0); T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2B0, cnt | 0x8000); - MMU.sqrtCycles = (nds.cycles + 26); + MMU.sqrtCycles = nds_timer + 26; MMU.sqrtResult = ret; MMU.sqrtCnt = (cnt & 0x7FFF); MMU.sqrtRunning = TRUE; + NDS_Reschedule(); } static void execdiv() { @@ -1078,19 +1062,19 @@ static void execdiv() { case 0: num = (s64) (s32) T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x290); den = (s64) (s32) T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x298); - MMU.divCycles = (nds.cycles + 36); + MMU.divCycles = nds_timer + 36; break; case 1: case 3: //gbatek says this is same as mode 1 num = (s64) T1ReadQuad(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x290); den = (s64) (s32) T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x298); - MMU.divCycles = (nds.cycles + 68); + MMU.divCycles = nds_timer + 68; break; case 2: default: num = (s64) T1ReadQuad(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x290); den = (s64) T1ReadQuad(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x298); - MMU.divCycles = (nds.cycles + 68); + MMU.divCycles = nds_timer + 68; break; } @@ -1122,6 +1106,7 @@ static void execdiv() { MMU.divMod = mod; MMU.divCnt = (cnt & 0x7FFF); MMU.divRunning = TRUE; + NDS_Reschedule(); } template @@ -1150,19 +1135,21 @@ void FASTCALL MMU_doDMA(u32 num) taille = (MMU.DMACrt[PROCNUM][num]&0x1FFFFF); if(taille == 0) taille = 0x200000; //according to gbatek.. + //THIS IS A BIG HACK // If we are in "Main memory display" mode just copy an entire // screen (256x192 pixels). // Reference: http://nocash.emubase.de/gbatek.htm#dsvideocaptureandmainmemorydisplaymode // (under DISP_MMEM_FIFO) - if ((MMU.DMAStartTime[PROCNUM][num]==4) && // Must be in main memory display mode + if ((MMU.DMAStartTime[PROCNUM][num]==EDMAMode_MemDisplay) && // Must be in main memory display mode (taille==4) && // Word must be 4 (((MMU.DMACrt[PROCNUM][num]>>26)&1) == 1)) // Transfer mode must be 32bit wide taille = 24576; //256*192/2; - if(MMU.DMAStartTime[PROCNUM][num] == 5) + if(MMU.DMAStartTime[PROCNUM][num] == EDMAMode_Card) taille *= 0x80; - MMU.DMACycle[PROCNUM][num] = taille + nds.cycles; + MMU.DMACycle[PROCNUM][num] = taille + nds_timer; //TODO - surely this is a gross simplification + MMU.DMAing[PROCNUM][num] = TRUE; MMU.CheckDMAs |= (1<<(num+(PROCNUM<<2))); @@ -1172,6 +1159,8 @@ void FASTCALL MMU_doDMA(u32 num) if(!(MMU.DMACrt[PROCNUM][num]&(1<<25))) MMU.DMAStartTime[PROCNUM][num] = 0; + + NDS_RescheduleDMA(); // transfer { @@ -1315,6 +1304,97 @@ static INLINE void MMU_IPCSync(u8 proc, u32 val) setIF(proc^1, ( 1 << 16 )); } +static INLINE u16 read_timer(int proc, int timerIndex) +{ + //chained timers are always up to date + if(MMU.timerMODE[proc][timerIndex] == 0xFFFF) + return MMU.timer[proc][timerIndex]; + + //for unchained timers, we do not keep the timer up to date. its value will need to be calculated here + s32 diff = (s32)(nds.timerCycle[proc][timerIndex] - nds_timer); + assert(diff>=0); + if(diff<0) + printf("NEW EMULOOP BAD NEWS PLEASE REPORT: TIME READ DIFF < 0 (%d) (%d) (%d)\n",diff,timerIndex,MMU.timerMODE[proc][timerIndex]); + + s32 units = diff / (1<=0); + if(ret<0) printf("NEW EMULOOP BAD NEWS PLEASE REPORT: TIME READ RETURN < 0\n"); + return ret; +} + +static INLINE void write_timer(int proc, int timerIndex, u16 val) +{ + int mask = ((val&0x80)>>7) << timerIndex; + //MMU.CheckTimers = (MMU.CheckTimers & (~mask)) | mask; + + if(val&0x80) + MMU.timer[proc][timerIndex] = MMU.timerReload[proc][timerIndex]; + + MMU.timerON[proc][timerIndex] = val & 0x80; + + switch(val&7) + { + case 0 : + MMU.timerMODE[proc][timerIndex] = 0+1; + break; + case 1 : + MMU.timerMODE[proc][timerIndex] = 6+1; + break; + case 2 : + MMU.timerMODE[proc][timerIndex] = 8+1; + break; + case 3 : + MMU.timerMODE[proc][timerIndex] = 10+1; + break; + default : + MMU.timerMODE[proc][timerIndex] = 0xFFFF; + break; + } + + int remain = 65536 - MMU.timerReload[proc][timerIndex]; + nds.timerCycle[proc][timerIndex] = nds_timer + (remain< static INLINE void write_dma_hictrl(const int dmanum, const u16 val) +{ + u32 baseAddr = 0xB0 + dmanum*12; + + //write this control value + T1WriteWord(MMU.MMU_MEM[proc][0x40], baseAddr+10, val); + + //read back the src and dst addr + DMASrc[proc][dmanum] = T1ReadLong(MMU.MMU_MEM[proc][0x40], baseAddr); + DMADst[proc][dmanum] = T1ReadLong(MMU.MMU_MEM[proc][0x40], baseAddr+4); + + //analyze the control value + u32 v = T1ReadLong(MMU.MMU_MEM[proc][0x40], baseAddr+8); + if(proc==ARMCPU_ARM9) MMU.DMAStartTime[proc][dmanum] = (v>>27) & 0x7; + else { + static const EDMAMode lookup[] = {EDMAMode_Immediate,EDMAMode_VBlank,EDMAMode_Card,EDMAMode7_Wifi}; + MMU.DMAStartTime[proc][dmanum] = lookup[(v>>28) & 0x3]; + if(MMU.DMAStartTime[proc][dmanum] == EDMAMode7_Wifi && (dmanum==1 || dmanum==3)) + MMU.DMAStartTime[proc][dmanum] = EDMAMode7_GBASlot; + } + MMU.DMACrt[proc][dmanum] = v; + if(MMU.DMAStartTime[proc][dmanum] == EDMAMode_Immediate + //TODO HACK: I think this is a gxfifo hack: + || MMU.DMAStartTime[proc][dmanum] == EDMAMode_GXFifo) + { + MMU_doDMA(dmanum); + } + + //printf("dma ctrl %d %d\n",proc,dmanum); + + //LOG("ARMCPU_ARM9 %d, dma %d src %08X dst %08X %s\r\n", ARMCPU_ARM9, 0, DMASrc[ARMCPU_ARM9][0], DMADst[ARMCPU_ARM9][0], (val&(1<<25))?"ON":"OFF"); + + NDS_RescheduleDMA(); +} + static INLINE void write_auxspicnt(const int proc, const int size, const int adr, const int val) { //why val==0 to reset? is it a particular bit? its not bit 6... @@ -1869,6 +1949,7 @@ void FASTCALL _MMU_ARM9_write16(u32 adr, u16 val) case REG_IME: { + NDS_Reschedule(); u32 old_val = MMU.reg_IME[ARMCPU_ARM9]; u32 new_val = val & 0x01; MMU.reg_IME[ARMCPU_ARM9] = new_val; @@ -1887,6 +1968,7 @@ void FASTCALL _MMU_ARM9_write16(u32 adr, u16 val) return; } case REG_IE : + NDS_Reschedule(); MMU.reg_IE[ARMCPU_ARM9] = (MMU.reg_IE[ARMCPU_ARM9]&0xFFFF0000) | val; #ifndef NEW_IRQ if ( MMU.reg_IME[ARMCPU_ARM9]) @@ -1901,6 +1983,7 @@ void FASTCALL _MMU_ARM9_write16(u32 adr, u16 val) #endif return; case REG_IE + 2 : + NDS_Reschedule(); MMU.reg_IE[ARMCPU_ARM9] = (MMU.reg_IE[ARMCPU_ARM9]&0xFFFF) | (((u32)val)<<16); #ifndef NEW_IRQ if ( MMU.reg_IME[ARMCPU_ARM9]) @@ -1916,9 +1999,11 @@ void FASTCALL _MMU_ARM9_write16(u32 adr, u16 val) return; case REG_IF : + NDS_Reschedule(); MMU.reg_IF[ARMCPU_ARM9] &= (~((u32)val)); return; case REG_IF + 2 : + NDS_Reschedule(); MMU.reg_IF[ARMCPU_ARM9] &= (~(((u32)val)<<16)); return; @@ -1941,37 +2026,7 @@ void FASTCALL _MMU_ARM9_write16(u32 adr, u16 val) case REG_TM3CNTH : { int timerIndex = ((adr-2)>>2)&0x3; - int mask = ((val&0x80)>>7) << timerIndex; - MMU.CheckTimers = (MMU.CheckTimers & (~mask)) | mask; - - if(val&0x80) - MMU.timer[ARMCPU_ARM9][timerIndex] = MMU.timerReload[ARMCPU_ARM9][((adr-2)>>2)&0x3]; - - MMU.timerON[ARMCPU_ARM9][((adr-2)>>2)&0x3] = val & 0x80; - - switch(val&7) - { - case 0 : - MMU.timerMODE[ARMCPU_ARM9][timerIndex] = 0+1;//ARMCPU_ARM9; - break; - case 1 : - MMU.timerMODE[ARMCPU_ARM9][timerIndex] = 6+1;//ARMCPU_ARM9; - break; - case 2 : - MMU.timerMODE[ARMCPU_ARM9][timerIndex] = 8+1;//ARMCPU_ARM9; - break; - case 3 : - MMU.timerMODE[ARMCPU_ARM9][timerIndex] = 10+1;//ARMCPU_ARM9; - break; - default : - MMU.timerMODE[ARMCPU_ARM9][timerIndex] = 0xFFFF; - break; - } - - if(!(val & 0x80)) - MMU.timerRUN[ARMCPU_ARM9][timerIndex] = FALSE; - - T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM9][0x40], adr & 0xFFF, val); + write_timer(ARMCPU_ARM9, timerIndex, val); return; } @@ -2021,95 +2076,17 @@ void FASTCALL _MMU_ARM9_write16(u32 adr, u16 val) } case REG_DMA0CNTH : - { - u32 v; - //if(val&0x8000) emu_halt(); - //LOG("16 bit dma0 %04X\r\n", val); - T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0xBA, val); - DMASrc[ARMCPU_ARM9][0] = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0xB0); - DMADst[ARMCPU_ARM9][0] = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0xB4); - DMAtoVRAMmapping<0>(); - v = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0xB8); - MMU.DMAStartTime[ARMCPU_ARM9][0] = (v>>27) & 0x7; - MMU.DMACrt[ARMCPU_ARM9][0] = v; - if(MMU.DMAStartTime[ARMCPU_ARM9][0] == 0) - MMU_doDMA(0); - #ifdef LOG_DMA2 - //else - { - LOG("ARMCPU_ARM9 %d, dma %d src %08X dst %08X %s\r\n", ARMCPU_ARM9, 0, DMASrc[ARMCPU_ARM9][0], DMADst[ARMCPU_ARM9][0], (val&(1<<25))?"ON":"OFF"); - } - #endif - } + write_dma_hictrl(0,val); return; case REG_DMA1CNTH : - { - u32 v; - //if(val&0x8000) emu_halt(); - //LOG("16 bit dma1 %04X\r\n", val); - T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0xC6, val); - DMASrc[ARMCPU_ARM9][1] = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0xBC); - DMADst[ARMCPU_ARM9][1] = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0xC0); - DMAtoVRAMmapping<1>(); - v = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0xC4); - MMU.DMAStartTime[ARMCPU_ARM9][1] = (v>>27) & 0x7; - MMU.DMACrt[ARMCPU_ARM9][1] = v; - if(MMU.DMAStartTime[ARMCPU_ARM9][1] == 0) - MMU_doDMA(1); - #ifdef LOG_DMA2 - //else - { - LOG("ARMCPU_ARM9 %d, dma %d src %08X dst %08X %s\r\n", ARMCPU_ARM9, 1, DMASrc[ARMCPU_ARM9][1], DMADst[ARMCPU_ARM9][1], (val&(1<<25))?"ON":"OFF"); - } - #endif - } + write_dma_hictrl(1,val); return; case REG_DMA2CNTH : - { - u32 v; - //if(val&0x8000) emu_halt(); - //LOG("16 bit dma2 %04X\r\n", val); - T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0xD2, val); - DMASrc[ARMCPU_ARM9][2] = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0xC8); - DMADst[ARMCPU_ARM9][2] = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0xCC); - DMAtoVRAMmapping<2>(); - v = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0xD0); - MMU.DMAStartTime[ARMCPU_ARM9][2] = (v>>27) & 0x7; - MMU.DMACrt[ARMCPU_ARM9][2] = v; - if(MMU.DMAStartTime[ARMCPU_ARM9][2] == 0) - MMU_doDMA(2); - #ifdef LOG_DMA2 - //else - { - LOG("ARMCPU_ARM9 %d, dma %d src %08X dst %08X %s\r\n", ARMCPU_ARM9, 2, DMASrc[ARMCPU_ARM9][2], DMADst[ARMCPU_ARM9][2], (val&(1<<25))?"ON":"OFF"); - } - #endif - } + write_dma_hictrl(2,val); return; case REG_DMA3CNTH : - { - u32 v; - //if(val&0x8000) emu_halt(); - //LOG("16 bit dma3 %04X\r\n", val); - T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0xDE, val); - DMASrc[ARMCPU_ARM9][3] = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0xD4); - DMADst[ARMCPU_ARM9][3] = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0xD8); - DMAtoVRAMmapping<3>(); - v = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0xDC); - MMU.DMAStartTime[ARMCPU_ARM9][3] = (v>>27) & 0x7; - MMU.DMACrt[ARMCPU_ARM9][3] = v; - - if(MMU.DMAStartTime[ARMCPU_ARM9][3] == 0) - MMU_doDMA(3); - #ifdef LOG_DMA2 - //else - { - LOG("ARMCPU_ARM9 %d, dma %d src %08X dst %08X %s\r\n", ARMCPU_ARM9, 3, DMASrc[ARMCPU_ARM9][3], DMADst[ARMCPU_ARM9][3], (val&(1<<25))?"ON":"OFF"); - } - #endif - } + write_dma_hictrl(3,val); return; - //case REG_AUXSPICNT : emu_halt(); case REG_DISPA_DISPMMEMFIFO: { DISP_FIFOsend(val); @@ -2382,6 +2359,7 @@ void FASTCALL _MMU_ARM9_write32(u32 adr, u32 val) case REG_IME : { + NDS_Reschedule(); u32 old_val = MMU.reg_IME[ARMCPU_ARM9]; u32 new_val = val & 0x01; MMU.reg_IME[ARMCPU_ARM9] = new_val; @@ -2401,6 +2379,7 @@ void FASTCALL _MMU_ARM9_write32(u32 adr, u32 val) return; case REG_IE : + NDS_Reschedule(); MMU.reg_IE[ARMCPU_ARM9] = val; #ifndef NEW_IRQ if ( MMU.reg_IME[ARMCPU_ARM9]) @@ -2416,6 +2395,7 @@ void FASTCALL _MMU_ARM9_write32(u32 adr, u32 val) return; case REG_IF : + NDS_Reschedule(); MMU.reg_IF[ARMCPU_ARM9] &= (~val); return; @@ -2425,36 +2405,9 @@ void FASTCALL _MMU_ARM9_write32(u32 adr, u32 val) case REG_TM3CNTL: { int timerIndex = (adr>>2)&0x3; - int mask = ((val & 0x800000)>>(16+7)) << timerIndex; - MMU.CheckTimers = (MMU.CheckTimers & (~mask)) | mask; - MMU.timerReload[ARMCPU_ARM9][timerIndex] = (u16)val; - if(val&0x800000) - MMU.timer[ARMCPU_ARM9][timerIndex] = MMU.timerReload[ARMCPU_ARM9][(adr>>2)&0x3]; - - MMU.timerON[ARMCPU_ARM9][timerIndex] = val & 0x800000; - switch((val>>16)&7) - { - case 0 : - MMU.timerMODE[ARMCPU_ARM9][timerIndex] = 0+1;//ARMCPU_ARM9; - break; - case 1 : - MMU.timerMODE[ARMCPU_ARM9][timerIndex] = 6+1;//ARMCPU_ARM9; - break; - case 2 : - MMU.timerMODE[ARMCPU_ARM9][timerIndex] = 8+1;//ARMCPU_ARM9; - break; - case 3 : - MMU.timerMODE[ARMCPU_ARM9][timerIndex] = 10+1;//ARMCPU_ARM9; - break; - default : - MMU.timerMODE[ARMCPU_ARM9][timerIndex] = 0xFFFF; - break; - } - if(!(val & 0x800000)) - MMU.timerRUN[ARMCPU_ARM9][timerIndex] = FALSE; - - T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], adr & 0xFFF, val); + T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM9][0x40], adr & 0xFFF, val); + write_timer(ARMCPU_ARM9, timerIndex, val>>16); return; } @@ -2492,77 +2445,20 @@ void FASTCALL _MMU_ARM9_write32(u32 adr, u32 val) return; case REG_DMA0CNTL : - //LOG("32 bit dma0 %04X\r\n", val); - DMASrc[ARMCPU_ARM9][0] = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0xB0); - DMADst[ARMCPU_ARM9][0] = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0xB4); - DMAtoVRAMmapping<0>(); - MMU.DMAStartTime[ARMCPU_ARM9][0] = (val>>27) & 0x7; - MMU.DMACrt[ARMCPU_ARM9][0] = val; - T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0xB8, val); - if( MMU.DMAStartTime[ARMCPU_ARM9][0] == 0 || - MMU.DMAStartTime[ARMCPU_ARM9][0] == 7) // Start Immediately - MMU_doDMA(0); - #ifdef LOG_DMA2 - else - { - LOG("ARMCPU_ARM9 %d, dma %d src %08X dst %08X start taille %d %d\r\n", ARMCPU_ARM9, 0, DMASrc[ARMCPU_ARM9][0], DMADst[ARMCPU_ARM9][0], 0, ((MMU.DMACrt[ARMCPU_ARM9][0]>>27)&7)); - } - #endif - //emu_halt(); + T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0xB8, val); //write the low word + write_dma_hictrl(0,val>>16); return; case REG_DMA1CNTL: - //LOG("32 bit dma1 %04X\r\n", val); - DMASrc[ARMCPU_ARM9][1] = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0xBC); - DMADst[ARMCPU_ARM9][1] = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0xC0); - DMAtoVRAMmapping<1>(); - MMU.DMAStartTime[ARMCPU_ARM9][1] = (val>>27) & 0x7; - MMU.DMACrt[ARMCPU_ARM9][1] = val; - T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0xC4, val); - if(MMU.DMAStartTime[ARMCPU_ARM9][1] == 0 || - MMU.DMAStartTime[ARMCPU_ARM9][1] == 7) // Start Immediately - MMU_doDMA(1); - #ifdef LOG_DMA2 - else - { - LOG("ARMCPU_ARM9 %d, dma %d src %08X dst %08X start taille %d %d\r\n", ARMCPU_ARM9, 1, DMASrc[ARMCPU_ARM9][1], DMADst[ARMCPU_ARM9][1], 0, ((MMU.DMACrt[ARMCPU_ARM9][1]>>27)&7)); - } - #endif + T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0xC4, val); //write the low word + write_dma_hictrl(1,val>>16); return; case REG_DMA2CNTL : - //LOG("32 bit dma2 %04X\r\n", val); - DMASrc[ARMCPU_ARM9][2] = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0xC8); - DMADst[ARMCPU_ARM9][2] = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0xCC); - DMAtoVRAMmapping<2>(); - MMU.DMAStartTime[ARMCPU_ARM9][2] = (val>>27) & 0x7; - MMU.DMACrt[ARMCPU_ARM9][2] = val; - T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0xD0, val); - if(MMU.DMAStartTime[ARMCPU_ARM9][2] == 0 || - MMU.DMAStartTime[ARMCPU_ARM9][2] == 7) // Start Immediately - MMU_doDMA(2); - #ifdef LOG_DMA2 - else - { - LOG("ARMCPU_ARM9 %d, dma %d src %08X dst %08X start taille %d %d\r\n", ARMCPU_ARM9, 2, DMASrc[ARMCPU_ARM9][2], DMADst[ARMCPU_ARM9][2], 0, ((MMU.DMACrt[ARMCPU_ARM9][2]>>27)&7)); - } - #endif + T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0xD0, val); //write the low word + write_dma_hictrl(2,val>>16); return; case REG_DMA3CNTL : - //LOG("32 bit dma3 %04X\r\n", val); - DMASrc[ARMCPU_ARM9][3] = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0xD4); - DMADst[ARMCPU_ARM9][3] = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0xD8); - DMAtoVRAMmapping<3>(); - MMU.DMAStartTime[ARMCPU_ARM9][3] = (val>>27) & 0x7; - MMU.DMACrt[ARMCPU_ARM9][3] = val; - T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0xDC, val); - if( MMU.DMAStartTime[ARMCPU_ARM9][3] == 0 || - MMU.DMAStartTime[ARMCPU_ARM9][3] == 7) // Start Immediately - MMU_doDMA(3); - #ifdef LOG_DMA2 - else - { - LOG("ARMCPU_ARM9 %d, dma %d src %08X dst %08X start taille %d %d\r\n", ARMCPU_ARM9, 3, DMASrc[ARMCPU_ARM9][3], DMADst[ARMCPU_ARM9][3], 0, ((MMU.DMACrt[ARMCPU_ARM9][3]>>27)&7)); - } - #endif + T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0xDC, val); //write the low word + write_dma_hictrl(3,val>>16); return; case REG_GCROMCTRL : { @@ -2640,23 +2536,11 @@ void FASTCALL _MMU_ARM9_write32(u32 adr, u32 val) val |= 0x00800000; T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x1A4, val); - /* launch DMA if start flag was set to "DS Cart" */ - if(MMU.DMAStartTime[ARMCPU_ARM9][0] == 5) - { - MMU_doDMA(0); - } - if(MMU.DMAStartTime[ARMCPU_ARM9][1] == 5) - { - MMU_doDMA(1); - } - if(MMU.DMAStartTime[ARMCPU_ARM9][2] == 5) - { - MMU_doDMA(2); - } - if(MMU.DMAStartTime[ARMCPU_ARM9][3] == 5) - { - MMU_doDMA(3); - } + //launch DMA if start flag was set to "DS Cart" + if(MMU.DMAStartTime[ARMCPU_ARM9][0] == EDMAMode_Card) MMU_doDMA(0); + if(MMU.DMAStartTime[ARMCPU_ARM9][1] == EDMAMode_Card) MMU_doDMA(1); + if(MMU.DMAStartTime[ARMCPU_ARM9][2] == EDMAMode_Card) MMU_doDMA(2); + if(MMU.DMAStartTime[ARMCPU_ARM9][3] == EDMAMode_Card) MMU_doDMA(3); } return; case REG_DISPA_DISPCAPCNT : @@ -2768,7 +2652,7 @@ u16 FASTCALL _MMU_ARM9_read16(u32 adr) case REG_TM1CNTL : case REG_TM2CNTL : case REG_TM3CNTL : - return MMU.timer[ARMCPU_ARM9][(adr&0xF)>>2]; + return read_timer(ARMCPU_ARM9,(adr&0xF)>>2); case REG_AUXSPICNT: return MMU.AUX_SPI_CNT; @@ -3246,6 +3130,7 @@ void FASTCALL _MMU_ARM7_write16(u32 adr, u16 val) case REG_IME : { + NDS_Reschedule(); u32 old_val = MMU.reg_IME[ARMCPU_ARM7]; u32 new_val = val & 1; MMU.reg_IME[ARMCPU_ARM7] = new_val; @@ -3264,6 +3149,7 @@ void FASTCALL _MMU_ARM7_write16(u32 adr, u16 val) return; } case REG_IE : + NDS_Reschedule(); MMU.reg_IE[ARMCPU_ARM7] = (MMU.reg_IE[ARMCPU_ARM7]&0xFFFF0000) | val; #ifndef NEW_IRQ if ( MMU.reg_IME[ARMCPU_ARM7]) @@ -3278,6 +3164,7 @@ void FASTCALL _MMU_ARM7_write16(u32 adr, u16 val) #endif return; case REG_IE + 2 : + NDS_Reschedule(); //emu_halt(); MMU.reg_IE[ARMCPU_ARM7] = (MMU.reg_IE[ARMCPU_ARM7]&0xFFFF) | (((u32)val)<<16); #ifndef NEW_IRQ @@ -3294,10 +3181,12 @@ void FASTCALL _MMU_ARM7_write16(u32 adr, u16 val) return; case REG_IF : + NDS_Reschedule(); //emu_halt(); MMU.reg_IF[ARMCPU_ARM7] &= (~((u32)val)); return; case REG_IF + 2 : + NDS_Reschedule(); //emu_halt(); MMU.reg_IF[ARMCPU_ARM7] &= (~(((u32)val)<<16)); return; @@ -3321,127 +3210,22 @@ void FASTCALL _MMU_ARM7_write16(u32 adr, u16 val) case REG_TM3CNTH : { int timerIndex = ((adr-2)>>2)&0x3; - int mask = ((val&0x80)>>7) << (timerIndex+(ARMCPU_ARM7<<2)); - MMU.CheckTimers = (MMU.CheckTimers & (~mask)) | mask; - - if(val&0x80) - MMU.timer[ARMCPU_ARM7][timerIndex] = MMU.timerReload[ARMCPU_ARM7][((adr-2)>>2)&0x3]; - - MMU.timerON[ARMCPU_ARM7][((adr-2)>>2)&0x3] = val & 0x80; - - switch(val&7) - { - case 0 : - MMU.timerMODE[ARMCPU_ARM7][timerIndex] = 0+1;//ARMCPU_ARM7; - break; - case 1 : - MMU.timerMODE[ARMCPU_ARM7][timerIndex] = 6+1;//ARMCPU_ARM7; - break; - case 2 : - MMU.timerMODE[ARMCPU_ARM7][timerIndex] = 8+1;//ARMCPU_ARM7; - break; - case 3 : - MMU.timerMODE[ARMCPU_ARM7][timerIndex] = 10+1;//ARMCPU_ARM7; - break; - default : - MMU.timerMODE[ARMCPU_ARM7][timerIndex] = 0xFFFF; - break; - } - - if(!(val & 0x80)) - MMU.timerRUN[ARMCPU_ARM7][timerIndex] = FALSE; - - T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM7][0x40], adr & 0xFFF, val); + write_timer(ARMCPU_ARM7, timerIndex, val); return; } case REG_DMA0CNTH : - { - u32 v; - - //if(val&0x8000) emu_halt(); - //LOG("16 bit dma0 %04X\r\n", val); - T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0xBA, val); - DMASrc[ARMCPU_ARM7][0] = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0xB0); - DMADst[ARMCPU_ARM7][0] = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0xB4); - v = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0xB8); - MMU.DMAStartTime[ARMCPU_ARM7][0] = (v>>28) & 0x3; - MMU.DMACrt[ARMCPU_ARM7][0] = v; - if(MMU.DMAStartTime[ARMCPU_ARM7][0] == 0) - MMU_doDMA(0); - #ifdef LOG_DMA2 - //else - { - LOG("ARMCPU_ARM7 %d, dma %d src %08X dst %08X %s\r\n", ARMCPU_ARM7, 0, DMASrc[ARMCPU_ARM7][0], DMADst[ARMCPU_ARM7][0], (val&(1<<25))?"ON":"OFF"); - } - #endif - } + write_dma_hictrl(0,val); return; case REG_DMA1CNTH : - { - u32 v; - //if(val&0x8000) emu_halt(); - //LOG("16 bit dma1 %04X\r\n", val); - T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0xC6, val); - DMASrc[ARMCPU_ARM7][1] = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0xBC); - DMADst[ARMCPU_ARM7][1] = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0xC0); - v = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0xC4); - MMU.DMAStartTime[ARMCPU_ARM7][1] = (v>>28) & 0x3; - MMU.DMACrt[ARMCPU_ARM7][1] = v; - if(MMU.DMAStartTime[ARMCPU_ARM7][1] == 0) - MMU_doDMA(1); - #ifdef LOG_DMA2 - //else - { - LOG("ARMCPU_ARM7 %d, dma %d src %08X dst %08X %s\r\n", ARMCPU_ARM7, 1, DMASrc[ARMCPU_ARM7][1], DMADst[ARMCPU_ARM7][1], (val&(1<<25))?"ON":"OFF"); - } - #endif - } + write_dma_hictrl(1,val); return; case REG_DMA2CNTH : - { - u32 v; - //if(val&0x8000) emu_halt(); - //LOG("16 bit dma2 %04X\r\n", val); - T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0xD2, val); - DMASrc[ARMCPU_ARM7][2] = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0xC8); - DMADst[ARMCPU_ARM7][2] = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0xCC); - v = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0xD0); - MMU.DMAStartTime[ARMCPU_ARM7][2] = (v>>28) & 0x3; - MMU.DMACrt[ARMCPU_ARM7][2] = v; - if(MMU.DMAStartTime[ARMCPU_ARM7][2] == 0) - MMU_doDMA(2); - #ifdef LOG_DMA2 - //else - { - LOG("ARMCPU_ARM7 %d, dma %d src %08X dst %08X %s\r\n", ARMCPU_ARM7, 2, DMASrc[ARMCPU_ARM7][2], DMADst[ARMCPU_ARM7][2], (val&(1<<25))?"ON":"OFF"); - } - #endif - } + write_dma_hictrl(2,val); return; case REG_DMA3CNTH : - { - u32 v; - //if(val&0x8000) emu_halt(); - //LOG("16 bit dma3 %04X\r\n", val); - T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0xDE, val); - DMASrc[ARMCPU_ARM7][3] = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0xD4); - DMADst[ARMCPU_ARM7][3] = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0xD8); - v = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0xDC); - MMU.DMAStartTime[ARMCPU_ARM7][3] = (v>>28) & 0x3; - MMU.DMACrt[ARMCPU_ARM7][3] = v; - - if(MMU.DMAStartTime[ARMCPU_ARM7][3] == 0) - MMU_doDMA(3); - #ifdef LOG_DMA2 - //else - { - LOG("ARMCPU_ARM7 %d, dma %d src %08X dst %08X %s\r\n", ARMCPU_ARM7, 3, DMASrc[ARMCPU_ARM7][3], DMADst[ARMCPU_ARM7][3], (val&(1<<25))?"ON":"OFF"); - } - #endif - } + write_dma_hictrl(3,val); return; - //case REG_AUXSPICNT : emu_halt(); } T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM7][0x40], adr&MMU.MMU_MASK[ARMCPU_ARM7][adr>>20], val); @@ -3497,6 +3281,7 @@ void FASTCALL _MMU_ARM7_write32(u32 adr, u32 val) case REG_IME : { + NDS_Reschedule(); u32 old_val = MMU.reg_IME[ARMCPU_ARM7]; u32 new_val = val & 1; MMU.reg_IME[ARMCPU_ARM7] = new_val; @@ -3516,6 +3301,7 @@ void FASTCALL _MMU_ARM7_write32(u32 adr, u32 val) } case REG_IE : + NDS_Reschedule(); MMU.reg_IE[ARMCPU_ARM7] = val; #ifndef NEW_IRQ if ( MMU.reg_IME[ARMCPU_ARM7]) @@ -3531,6 +3317,7 @@ void FASTCALL _MMU_ARM7_write32(u32 adr, u32 val) return; case REG_IF : + NDS_Reschedule(); MMU.reg_IF[ARMCPU_ARM7] &= (~val); return; @@ -3540,38 +3327,13 @@ void FASTCALL _MMU_ARM7_write32(u32 adr, u32 val) case REG_TM3CNTL: { int timerIndex = (adr>>2)&0x3; - int mask = ((val & 0x800000)>>(16+7)) << (timerIndex+(ARMCPU_ARM7<<2)); - MMU.CheckTimers = (MMU.CheckTimers & (~mask)) | mask; - MMU.timerReload[ARMCPU_ARM7][timerIndex] = (u16)val; - if(val&0x800000) - MMU.timer[ARMCPU_ARM7][timerIndex] = MMU.timerReload[ARMCPU_ARM7][(adr>>2)&0x3]; - - MMU.timerON[ARMCPU_ARM7][timerIndex] = val & 0x800000; - switch((val>>16)&7) - { - case 0 : - MMU.timerMODE[ARMCPU_ARM7][timerIndex] = 0+1;//ARMCPU_ARM7; - break; - case 1 : - MMU.timerMODE[ARMCPU_ARM7][timerIndex] = 6+1;//ARMCPU_ARM7; - break; - case 2 : - MMU.timerMODE[ARMCPU_ARM7][timerIndex] = 8+1;//ARMCPU_ARM7; - break; - case 3 : - MMU.timerMODE[ARMCPU_ARM7][timerIndex] = 10+1;//ARMCPU_ARM7; - break; - default : - MMU.timerMODE[ARMCPU_ARM7][timerIndex] = 0xFFFF; - break; - } - if(!(val & 0x800000)) - MMU.timerRUN[ARMCPU_ARM7][timerIndex] = FALSE; - T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM7][0x40], adr & 0xFFF, val); + T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM7][0x40], adr & 0xFFF, val); + write_timer(ARMCPU_ARM7, timerIndex, val>>16); return; } + case REG_IPCSYNC : MMU_IPCSync(ARMCPU_ARM7, val); return; @@ -3579,75 +3341,24 @@ void FASTCALL _MMU_ARM7_write32(u32 adr, u32 val) case REG_IPCFIFOSEND : IPC_FIFOsend(ARMCPU_ARM7, val); return; + case REG_DMA0CNTL : - //LOG("32 bit dma0 %04X\r\n", val); - DMASrc[ARMCPU_ARM7][0] = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0xB0); - DMADst[ARMCPU_ARM7][0] = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0xB4); - MMU.DMAStartTime[ARMCPU_ARM7][0] = (val>>28) & 0x3; - MMU.DMACrt[ARMCPU_ARM7][0] = val; - T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0xB8, val); - if( MMU.DMAStartTime[ARMCPU_ARM7][0] == 0 || - MMU.DMAStartTime[ARMCPU_ARM7][0] == 7) // Start Immediately - MMU_doDMA(0); - #ifdef LOG_DMA2 - else - { - LOG("ARMCPU_ARM7 %d, dma %d src %08X dst %08X start taille %d %d\r\n", ARMCPU_ARM7, 0, DMASrc[ARMCPU_ARM7][0], DMADst[ARMCPU_ARM7][0], 0, ((MMU.DMACrt[ARMCPU_ARM7][0]>>27)&7)); - } - #endif - //emu_halt(); + T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0xB8, val); //write the low word + write_dma_hictrl(0,val>>16); return; case REG_DMA1CNTL: - //LOG("32 bit dma1 %04X\r\n", val); - DMASrc[ARMCPU_ARM7][1] = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0xBC); - DMADst[ARMCPU_ARM7][1] = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0xC0); - MMU.DMAStartTime[ARMCPU_ARM7][1] = (val>>28) & 0x3; - MMU.DMACrt[ARMCPU_ARM7][1] = val; - T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0xC4, val); - if(MMU.DMAStartTime[ARMCPU_ARM7][1] == 0 || - MMU.DMAStartTime[ARMCPU_ARM7][1] == 7) // Start Immediately - MMU_doDMA(1); - #ifdef LOG_DMA2 - else - { - LOG("ARMCPU_ARM7 %d, dma %d src %08X dst %08X start taille %d %d\r\n", ARMCPU_ARM7, 1, DMASrc[ARMCPU_ARM7][1], DMADst[ARMCPU_ARM7][1], 0, ((MMU.DMACrt[ARMCPU_ARM7][1]>>27)&7)); - } - #endif + T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0xC4, val); //write the low word + write_dma_hictrl(1,val>>16); return; case REG_DMA2CNTL : - //LOG("32 bit dma2 %04X\r\n", val); - DMASrc[ARMCPU_ARM7][2] = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0xC8); - DMADst[ARMCPU_ARM7][2] = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0xCC); - MMU.DMAStartTime[ARMCPU_ARM7][2] = (val>>28) & 0x3; - MMU.DMACrt[ARMCPU_ARM7][2] = val; - T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0xD0, val); - if(MMU.DMAStartTime[ARMCPU_ARM7][2] == 0 || - MMU.DMAStartTime[ARMCPU_ARM7][2] == 7) // Start Immediately - MMU_doDMA(2); - #ifdef LOG_DMA2 - else - { - LOG("ARMCPU_ARM7 %d, dma %d src %08X dst %08X start taille %d %d\r\n", ARMCPU_ARM7, 2, DMASrc[ARMCPU_ARM7][2], DMADst[ARMCPU_ARM7][2], 0, ((MMU.DMACrt[ARMCPU_ARM7][2]>>27)&7)); - } - #endif + T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0xD0, val); //write the low word + write_dma_hictrl(2,val>>16); return; case REG_DMA3CNTL : - //LOG("32 bit dma3 %04X\r\n", val); - DMASrc[ARMCPU_ARM7][3] = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0xD4); - DMADst[ARMCPU_ARM7][3] = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0xD8); - MMU.DMAStartTime[ARMCPU_ARM7][3] = (val>>28) & 0x3; - MMU.DMACrt[ARMCPU_ARM7][3] = val; - T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0xDC, val); - if( MMU.DMAStartTime[ARMCPU_ARM7][3] == 0 || - MMU.DMAStartTime[ARMCPU_ARM7][3] == 7) // Start Immediately - MMU_doDMA(3); - #ifdef LOG_DMA2 - else - { - LOG("ARMCPU_ARM7 %d, dma %d src %08X dst %08X start taille %d %d\r\n", ARMCPU_ARM7, 3, DMASrc[ARMCPU_ARM7][3], DMADst[ARMCPU_ARM7][3], 0, ((MMU.DMACrt[ARMCPU_ARM7][3]>>27)&7)); - } - #endif + T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0xDC, val); //write the low word + write_dma_hictrl(3,val>>16); return; + case REG_GCROMCTRL : { if(!(val & 0x80000000)) @@ -3707,16 +3418,11 @@ void FASTCALL _MMU_ARM7_write32(u32 adr, u32 val) val |= 0x00800000; T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0x1A4, val); - /* launch DMA if start flag was set to "DS Cart" */ - - if(MMU.DMAStartTime[ARMCPU_ARM7][2] == 2) - { - MMU_doDMA(2); - } - if(MMU.DMAStartTime[ARMCPU_ARM7][3] == 2) - { - MMU_doDMA(3); - } + //launch DMA if start flag was set to "DS Cart" + if(MMU.DMAStartTime[ARMCPU_ARM7][0] == EDMAMode_Card) MMU_doDMA(0); + if(MMU.DMAStartTime[ARMCPU_ARM7][1] == EDMAMode_Card) MMU_doDMA(1); + if(MMU.DMAStartTime[ARMCPU_ARM7][2] == EDMAMode_Card) MMU_doDMA(2); + if(MMU.DMAStartTime[ARMCPU_ARM7][3] == EDMAMode_Card) MMU_doDMA(3); return; @@ -3803,7 +3509,7 @@ u16 FASTCALL _MMU_ARM7_read16(u32 adr) case REG_TM1CNTL : case REG_TM2CNTL : case REG_TM3CNTL : - return MMU.timer[ARMCPU_ARM7][(adr&0xF)>>2]; + return read_timer(ARMCPU_ARM7,(adr&0xF)>>2); case REG_AUXSPICNT: return MMU.AUX_SPI_CNT; diff --git a/desmume/src/MMU.h b/desmume/src/MMU.h index 1c6d4c901..4858d3ed4 100644 --- a/desmume/src/MMU.h +++ b/desmume/src/MMU.h @@ -97,7 +97,7 @@ struct MMU_struct { u32 reg_IF[2]; u32 DMAStartTime[2][4]; - s32 DMACycle[2][4]; + u64 DMACycle[2][4]; u32 DMACrt[2][4]; BOOL DMAing[2][4]; @@ -105,21 +105,19 @@ struct MMU_struct { s64 divResult; s64 divMod; u32 divCnt; - s32 divCycles; + u64 divCycles; BOOL sqrtRunning; u32 sqrtResult; u32 sqrtCnt; - s32 sqrtCycles; + u64 sqrtCycles; u16 SPI_CNT; u16 SPI_CMD; u16 AUX_SPI_CNT; u16 AUX_SPI_CMD; -#ifdef USE_GEOMETRY_FIFO_EMULATION - s32 gfx3dCycles; -#endif + u64 gfx3dCycles; u8 powerMan_CntReg; BOOL powerMan_CntRegWritten; @@ -265,6 +263,20 @@ inline void SetupMMU(bool debugConsole) { //T1ReadWord(MMU.MMU_MEM[ARMCPU_ARM7][(adr >> 20) & 0xFF], // adr & MMU.MMU_MASK[ARMCPU_ARM7][(adr >> 20) & 0xFF]); +enum EDMAMode +{ + EDMAMode_Immediate = 0, + EDMAMode_VBlank = 1, + EDMAMode_HBlank = 2, + EDMAMode_HStart = 3, + EDMAMode_MemDisplay = 4, + EDMAMode_Card = 5, + EDMAMode_GBASlot = 6, + EDMAMode_GXFifo = 7, + EDMAMode7_Wifi = 8, + EDMAMode7_GBASlot = 9, +}; + FORCEINLINE u8 _MMU_read08(const int PROCNUM, const MMU_ACCESS_TYPE AT, const u32 addr) { //special handling for DMA: read 0 from TCM @@ -427,6 +439,10 @@ FORCEINLINE void _MMU_write16(const int PROCNUM, const MMU_ACCESS_TYPE AT, const FORCEINLINE void _MMU_write32(const int PROCNUM, const MMU_ACCESS_TYPE AT, const u32 addr, u32 val) { + if(addr == 0x022D7900) + { + int zzz=9; + } //special handling for DMA: discard writes to TCM if(PROCNUM==ARMCPU_ARM9 && AT == MMU_AT_DMA) { diff --git a/desmume/src/NDSSystem.cpp b/desmume/src/NDSSystem.cpp index e0d97e156..ae20db08f 100644 --- a/desmume/src/NDSSystem.cpp +++ b/desmume/src/NDSSystem.cpp @@ -40,11 +40,24 @@ #include "cheatSystem.h" #include "movie.h" #include "Disassembler.h" +#include "readwrite.h" #ifdef _WIN32 #include "./windows/disView.h" #endif +//this doesnt work anyway. why take a speed hit for public releases? +// Luigi__: I don't agree. We should start include wifi emulation in public releases +// because it already allows games to not hang during wifi operations +// and thus games that perform wifi checks upon boot shouldn't hang with wifi +// emulation turned on. +// zeromus: which games are these? I would like to see what happens. +// this is a substantial framerate hit. we should consider an emulation option +// to indicate whether this whole system should be enabled +#ifndef PUBLIC_RELEASE +#undef EXPERIMENTAL_WIFI +#endif + TCommonSettings CommonSettings; static BaseDriver _stub_driver; BaseDriver* driver = &_stub_driver; @@ -57,13 +70,16 @@ char pathFilenameToROMwithoutExt[MAX_PATH]; GameInfo gameInfo; -/* the count of bytes copied from the firmware into memory */ +// the count of bytes copied from the firmware into memory #define NDS_FW_USER_SETTINGS_MEM_BYTE_COUNT 0x70 BOOL fw_success = FALSE; NDSSystem nds; +using std::min; +using std::max; + int lagframecounter; int LagFrameFlag; int lastLag; @@ -496,15 +512,10 @@ struct armcpu_ctrl_iface **arm7_ctrl_iface) { #else int NDS_Init( void) { #endif - nds.ARM9Cycle = 0; - nds.ARM7Cycle = 0; - nds.cycles = 0; nds.idleFrameCounter = 0; memset(nds.runCycleCollector,0,sizeof(nds.runCycleCollector)); MMU_Init(); - nds.nextHBlank = 3168; nds.VCount = 0; - nds.lignerendu = FALSE; nds.sleeping = FALSE; @@ -539,7 +550,6 @@ void NDS_DeInit(void) { if(MMU.CART_ROM != MMU.UNUSED_RAM) NDS_FreeROM(); - nds.nextHBlank = 3168; SPU_DeInit(); Screen_DeInit(); MMU_DeInit(); @@ -889,206 +899,7 @@ void NDS_FreeROM(void) MMU.bupmem.fp = NULL; } -bool _HACK_DONT_STOPMOVIE = false; -void NDS_Reset() -{ - unsigned int i; - u32 src; - u32 dst; - FILE* inf = 0; - NDS_header * header = NDS_getROMHeader(); - if (!header) return ; - - if(movieMode != MOVIEMODE_INACTIVE && !_HACK_DONT_STOPMOVIE) - movie_reset_command = true; - - if(movieMode == MOVIEMODE_INACTIVE) { - currFrameCounter = 0; - lagframecounter = 0; - LagFrameFlag = 0; - lastLag = 0; - TotalLagFrames = 0; - } - - MMU_clearMem(); - MMU_new.backupDevice.reset(); - - //ARM7 BIOS IRQ HANDLER - if(CommonSettings.UseExtBIOS == true) - inf = fopen(CommonSettings.ARM7BIOS,"rb"); - else - inf = NULL; - - if(inf) { - fread(MMU.ARM7_BIOS,1,16384,inf); - fclose(inf); - if(CommonSettings.SWIFromBIOS == true) NDS_ARM7.swi_tab = 0; - else NDS_ARM7.swi_tab = ARM7_swi_tab; - INFO("ARM7 BIOS is loaded.\n"); - } else { - NDS_ARM7.swi_tab = ARM7_swi_tab; - _MMU_write32(0x00, 0xE25EF002); - _MMU_write32(0x04, 0xEAFFFFFE); - _MMU_write32(0x18, 0xEA000000); - _MMU_write32(0x20, 0xE92D500F); - _MMU_write32(0x24, 0xE3A00301); - _MMU_write32(0x28, 0xE28FE000); - _MMU_write32(0x2C, 0xE510F004); - _MMU_write32(0x30, 0xE8BD500F); - _MMU_write32(0x34, 0xE25EF004); - } - - //ARM9 BIOS IRQ HANDLER - if(CommonSettings.UseExtBIOS == true) - inf = fopen(CommonSettings.ARM9BIOS,"rb"); - else - inf = NULL; - //memcpy(ARM9Mem.ARM9_BIOS + 0x20, gba_header_data_0x04, 156); - - if(inf) { - fread(ARM9Mem.ARM9_BIOS,1,4096,inf); - fclose(inf); - if(CommonSettings.SWIFromBIOS == true) NDS_ARM9.swi_tab = 0; - else NDS_ARM9.swi_tab = ARM9_swi_tab; - INFO("ARM9 BIOS is loaded.\n"); - } else { - NDS_ARM9.swi_tab = ARM9_swi_tab; - _MMU_write32(0xFFFF0018, 0xEA000000); - _MMU_write32(0xFFFF0020, 0xE92D500F); - _MMU_write32(0xFFFF0024, 0xEE190F11); - _MMU_write32(0xFFFF0028, 0xE1A00620); - _MMU_write32(0xFFFF002C, 0xE1A00600); - _MMU_write32(0xFFFF0030, 0xE2800C40); - _MMU_write32(0xFFFF0034, 0xE28FE000); - _MMU_write32(0xFFFF0038, 0xE510F004); - _MMU_write32(0xFFFF003C, 0xE8BD500F); - _MMU_write32(0xFFFF0040, 0xE25EF004); - } - - /* Is it really needed ??? */ - _MMU_write32(0x0000004, 0xE3A0010E); - _MMU_write32(0x0000008, 0xE3A01020); - // _MMU_write32(0x000000C, 0xE1B02110); - _MMU_write32(0x000000C, 0xE1B02040); - _MMU_write32(0x0000010, 0xE3B02020); - // _MMU_write32(0x0000010, 0xE2100202); - - if(CommonSettings.UseExtFirmware == true) - NDS_LoadFirmware(CommonSettings.Firmware); - - if((CommonSettings.UseExtBIOS == true) && (CommonSettings.UseExtFirmware == true) && (CommonSettings.BootFromFirmware == true) && (fw_success == TRUE)) - { - for(i = 0; i < nds.FW_ARM9BootCodeSize; i += 4) - { - _MMU_write32((nds.FW_ARM9BootCodeAddr + i), T1ReadLong(nds.FW_ARM9BootCode, i)); - } - - for(i = 0; i < nds.FW_ARM7BootCodeSize; i += 4) - { - _MMU_write32((nds.FW_ARM7BootCodeAddr + i), T1ReadLong(nds.FW_ARM7BootCode, i)); - } - - armcpu_init(&NDS_ARM9, nds.FW_ARM9BootCodeAddr); - armcpu_init(&NDS_ARM7, nds.FW_ARM7BootCodeAddr); - //armcpu_init(&NDS_ARM9, 0xFFFF0000); - //armcpu_init(&NDS_ARM7, 0x00000000); - } - else - { - src = header->ARM9src; - dst = header->ARM9cpy; - - for(i = 0; i < (header->ARM9binSize>>2); ++i) - { - _MMU_write32(dst, T1ReadLong(MMU.CART_ROM, src)); - dst += 4; - src += 4; - } - - src = header->ARM7src; - dst = header->ARM7cpy; - - for(i = 0; i < (header->ARM7binSize>>2); ++i) - { - _MMU_write32(dst, T1ReadLong(MMU.CART_ROM, src)); - dst += 4; - src += 4; - } - - armcpu_init(&NDS_ARM7, header->ARM7exe); - armcpu_init(&NDS_ARM9, header->ARM9exe); - } - - nds.ARM9Cycle = 0; - nds.ARM7Cycle = 0; - nds.wifiCycle = 0; - nds.cycles = 0; - memset(nds.timerCycle, 0, sizeof(s32) * 2 * 4); - memset(nds.timerOver, 0, sizeof(BOOL) * 2 * 4); - nds.nextHBlank = 3168; - nds.VCount = 0; - nds.old = 0; - nds.diff = 0; - nds.lignerendu = FALSE; - nds.touchX = nds.touchY = 0; - nds.isTouch = 0; - nds.debugConsole = CommonSettings.DebugConsole; - SetupMMU(nds.debugConsole); - - _MMU_write16(0x04000130, 0x3FF); - _MMU_write16(0x04000130, 0x3FF); - _MMU_write08(0x04000136, 0x43); - - LidClosed = FALSE; - countLid = 0; - - /* - * Setup a copy of the firmware user settings in memory. - * (this is what the DS firmware would do). - */ - { - u8 temp_buffer[NDS_FW_USER_SETTINGS_MEM_BYTE_COUNT]; - int fw_index; - - if ( copy_firmware_user_data( temp_buffer, MMU.fw.data)) { - for ( fw_index = 0; fw_index < NDS_FW_USER_SETTINGS_MEM_BYTE_COUNT; fw_index++) - _MMU_write08(0x027FFC80 + fw_index, temp_buffer[fw_index]); - } - } - - // Copy the whole header to Main RAM 0x27FFE00 on startup. - // Reference: http://nocash.emubase.de/gbatek.htm#dscartridgeheader - //zero 27-jun-09 : why did this copy 0x90 more? gbatek says its not stored in ram. - //for (i = 0; i < ((0x170+0x90)/4); i++) { - for (i = 0; i < ((0x170)/4); i++) { - _MMU_write32(0x027FFE00+i*4, LE_TO_LOCAL_32(((u32*)MMU.CART_ROM)[i])); - } - - // Write the header checksum to memory (the firmware needs it to see the cart) - _MMU_write16(0x027FF808, T1ReadWord(MMU.CART_ROM, 0x15E)); - - MainScreen.offset = 0; - SubScreen.offset = 192; - - //_MMU_write32[ARMCPU_ARM9](0x02007FFC, 0xE92D4030); - - delete header; - - Screen_Reset(); - gfx3d_reset(); - gpu3D->NDS_3D_Reset(); - SPU_Reset(); - -#ifdef EXPERIMENTAL_WIFI - WIFI_Init(&wifiMac); - - WIFI_SoftAP_Shutdown(&wifiMac); - WIFI_SoftAP_Init(&wifiMac); -#endif - - memcpy(FW_Mac, (MMU.fw.data + 0x36), 6); -} int NDS_ImportSave(const char *filename) { @@ -1367,145 +1178,140 @@ int NDS_WriteBMP_32bppBuffer(int width, int height, const void* buf, const char } -static void -fill_user_data_area( struct NDS_fw_config_data *user_settings, - u8 *data, int count) { - u32 crc; - int i; - u8 *ts_cal_data_area; +static void fill_user_data_area( struct NDS_fw_config_data *user_settings,u8 *data, int count) +{ + u32 crc; + int i; + u8 *ts_cal_data_area; - memset( data, 0, 0x100); + memset( data, 0, 0x100); - /* version */ - data[0x00] = 5; - data[0x01] = 0; + // version + data[0x00] = 5; + data[0x01] = 0; - /* colour */ - data[0x02] = user_settings->fav_colour; + // colour + data[0x02] = user_settings->fav_colour; - /* birthday month and day */ - data[0x03] = user_settings->birth_month; - data[0x04] = user_settings->birth_day; + // birthday month and day + data[0x03] = user_settings->birth_month; + data[0x04] = user_settings->birth_day; - /* nickname and length */ - for ( i = 0; i < MAX_FW_NICKNAME_LENGTH; i++) { - data[0x06 + (i * 2)] = user_settings->nickname[i] & 0xff; - data[0x06 + (i * 2) + 1] = (user_settings->nickname[i] >> 8) & 0xff; - } + //nickname and length + for ( i = 0; i < MAX_FW_NICKNAME_LENGTH; i++) { + data[0x06 + (i * 2)] = user_settings->nickname[i] & 0xff; + data[0x06 + (i * 2) + 1] = (user_settings->nickname[i] >> 8) & 0xff; + } - data[0x1a] = user_settings->nickname_len; + data[0x1a] = user_settings->nickname_len; - /* Message */ - for ( i = 0; i < MAX_FW_MESSAGE_LENGTH; i++) { - data[0x1c + (i * 2)] = user_settings->message[i] & 0xff; - data[0x1c + (i * 2) + 1] = (user_settings->message[i] >> 8) & 0xff; - } + //Message + for ( i = 0; i < MAX_FW_MESSAGE_LENGTH; i++) { + data[0x1c + (i * 2)] = user_settings->message[i] & 0xff; + data[0x1c + (i * 2) + 1] = (user_settings->message[i] >> 8) & 0xff; + } - data[0x50] = user_settings->message_len; + data[0x50] = user_settings->message_len; - /* - * touch screen calibration - */ - ts_cal_data_area = &data[0x58]; - for ( i = 0; i < 2; i++) { - /* ADC x y */ - *ts_cal_data_area++ = user_settings->touch_cal[i].adc_x & 0xff; - *ts_cal_data_area++ = (user_settings->touch_cal[i].adc_x >> 8) & 0xff; - *ts_cal_data_area++ = user_settings->touch_cal[i].adc_y & 0xff; - *ts_cal_data_area++ = (user_settings->touch_cal[i].adc_y >> 8) & 0xff; + //touch screen calibration + ts_cal_data_area = &data[0x58]; + for ( i = 0; i < 2; i++) { + // ADC x y + *ts_cal_data_area++ = user_settings->touch_cal[i].adc_x & 0xff; + *ts_cal_data_area++ = (user_settings->touch_cal[i].adc_x >> 8) & 0xff; + *ts_cal_data_area++ = user_settings->touch_cal[i].adc_y & 0xff; + *ts_cal_data_area++ = (user_settings->touch_cal[i].adc_y >> 8) & 0xff; - /* screen x y */ - *ts_cal_data_area++ = user_settings->touch_cal[i].screen_x; - *ts_cal_data_area++ = user_settings->touch_cal[i].screen_y; - } + //screen x y + *ts_cal_data_area++ = user_settings->touch_cal[i].screen_x; + *ts_cal_data_area++ = user_settings->touch_cal[i].screen_y; + } - /* language and flags */ - data[0x64] = user_settings->language; - data[0x65] = 0xfc; + //language and flags + data[0x64] = user_settings->language; + data[0x65] = 0xfc; - /* update count and crc */ - data[0x70] = count & 0xff; - data[0x71] = (count >> 8) & 0xff; + //update count and crc + data[0x70] = count & 0xff; + data[0x71] = (count >> 8) & 0xff; - crc = calc_CRC16( 0xffff, data, 0x70); - data[0x72] = crc & 0xff; - data[0x73] = (crc >> 8) & 0xff; + crc = calc_CRC16( 0xffff, data, 0x70); + data[0x72] = crc & 0xff; + data[0x73] = (crc >> 8) & 0xff; - memset( &data[0x74], 0xff, 0x100 - 0x74); + memset( &data[0x74], 0xff, 0x100 - 0x74); } -/* creates an firmware flash image, which contains all needed info to initiate a wifi connection */ +// creates an firmware flash image, which contains all needed info to initiate a wifi connection int NDS_CreateDummyFirmware( struct NDS_fw_config_data *user_settings) { - /* - * Create the firmware header - */ + //Create the firmware header + memset( MMU.fw.data, 0, 0x40000); - /* firmware identifier */ + //firmware identifier MMU.fw.data[0x8] = 'M'; MMU.fw.data[0x8 + 1] = 'A'; MMU.fw.data[0x8 + 2] = 'C'; MMU.fw.data[0x8 + 3] = 'P'; - /* DS type */ + // DS type if ( user_settings->ds_type == NDS_FW_DS_TYPE_LITE) MMU.fw.data[0x1d] = 0x20; else MMU.fw.data[0x1d] = 0xff; - /* User Settings offset 0x3fe00 / 8 */ + //User Settings offset 0x3fe00 / 8 MMU.fw.data[0x20] = 0xc0; MMU.fw.data[0x21] = 0x7f; - /* - * User settings (at 0x3FE00 and 0x3FF00) - */ + //User settings (at 0x3FE00 and 0x3FF00) + fill_user_data_area( user_settings, &MMU.fw.data[ 0x3FE00], 0); fill_user_data_area( user_settings, &MMU.fw.data[ 0x3FF00], 1); - /* Wifi config length */ + // Wifi config length MMU.fw.data[0x2C] = 0x38; MMU.fw.data[0x2D] = 0x01; MMU.fw.data[0x2E] = 0x00; - /* Wifi version */ + //Wifi version MMU.fw.data[0x2F] = 0x00; - /* MAC address */ + //MAC address memcpy((MMU.fw.data + 0x36), FW_Mac, sizeof(FW_Mac)); - /* Enabled channels */ + //Enabled channels MMU.fw.data[0x3C] = 0xFE; MMU.fw.data[0x3D] = 0x3F; MMU.fw.data[0x3E] = 0xFF; MMU.fw.data[0x3F] = 0xFF; - /* RF related */ + //RF related MMU.fw.data[0x40] = 0x02; MMU.fw.data[0x41] = 0x18; MMU.fw.data[0x42] = 0x0C; MMU.fw.data[0x43] = 0x01; - /* Wifi I/O init values */ + //Wifi I/O init values memcpy((MMU.fw.data + 0x44), FW_WIFIInit, sizeof(FW_WIFIInit)); - /* Wifi BB init values */ + //Wifi BB init values memcpy((MMU.fw.data + 0x64), FW_BBInit, sizeof(FW_BBInit)); - /* Wifi RF init values */ + //Wifi RF init values memcpy((MMU.fw.data + 0xCE), FW_RFInit, sizeof(FW_RFInit)); - /* Wifi channel-related init values */ + //Wifi channel-related init values memcpy((MMU.fw.data + 0xF2), FW_RFChannel, sizeof(FW_RFChannel)); memcpy((MMU.fw.data + 0x146), FW_BBChannel, sizeof(FW_BBChannel)); memset((MMU.fw.data + 0x154), 0x10, 0xE); - /* WFC profiles */ + //WFC profiles memcpy((MMU.fw.data + 0x3FA40), &FW_WFCProfile1, sizeof(FW_WFCProfile)); memcpy((MMU.fw.data + 0x3FB40), &FW_WFCProfile2, sizeof(FW_WFCProfile)); memcpy((MMU.fw.data + 0x3FC40), &FW_WFCProfile3, sizeof(FW_WFCProfile)); @@ -1517,14 +1323,13 @@ int NDS_CreateDummyFirmware( struct NDS_fw_config_data *user_settings) MMU.fw.data[0x162] = 0x19; memset((MMU.fw.data + 0x163), 0xFF, 0x9D); - /* Wifi settings CRC16 */ + //Wifi settings CRC16 (*(u16*)(MMU.fw.data + 0x2A)) = calc_CRC16(0, (MMU.fw.data + 0x2C), 0x138); return TRUE ; } -void -NDS_FillDefaultFirmwareConfigData( struct NDS_fw_config_data *fw_config) { +void NDS_FillDefaultFirmwareConfigData( struct NDS_fw_config_data *fw_config) { const char *default_nickname = "yopyop"; const char *default_message = "DeSmuME makes you happy!"; int i; @@ -1617,10 +1422,643 @@ void NDS_SkipNextFrame() { SkipNext2DFrame = true; SkipCur3DFrame = true; } //#define LOG_ARM7 //static bool dolog = false; +void execHardware_doDma(int procnum, int chan, EDMAMode modeNum) +{ + if(MMU.DMAStartTime[procnum][chan] == modeNum) + { + if(procnum == ARMCPU_ARM9) MMU_doDMA(chan); + else MMU_doDMA(chan); + //MMU.DMAStartTime[procnum][chan] = 0; //this was here for main mem dma + } +} + +void execHardware_doAllDma(EDMAMode modeNum) +{ + for(int i=0;i<2;i++) + for(int j=0;j<4;j++) + execHardware_doDma(i,j,modeNum); +} + +enum ESI_DISPCNT +{ + ESI_DISPCNT_HStart, ESI_DISPCNT_HBlank +}; + +u64 nds_timer; +u64 nds_arm9_timer, nds_arm7_timer; + +static const u64 kNever = 0xFFFFFFFFFFFFFFFFULL; + +struct TSequenceItem +{ + u64 timestamp; + u32 param; + bool enabled; + + virtual void save(std::ostream* os) + { + write64le(timestamp,os); + write32le(param,os); + writebool(enabled,os); + } + + virtual bool load(std::istream* is) + { + if(read64le(×tamp,is) != 1) return false; + if(read32le(¶m,is) != 1) return false; + if(readbool(&enabled,is) != 1) return false; + return true; + } + + FORCEINLINE bool isTriggered() + { + return enabled && nds_timer >= timestamp; + } + + FORCEINLINE u64 next() + { + if(enabled) return timestamp; + else return kNever; + } +}; + +struct TSequenceItem_GXFIFO : public TSequenceItem +{ + FORCEINLINE bool isTriggered() + { + #ifndef USE_GEOMETRY_FIFO_EMULATION + return false; + #else + return enabled && nds_timer >= MMU.gfx3dCycles; + #endif + } + + FORCEINLINE void exec() + { + #ifdef USE_GEOMETRY_FIFO_EMULATION + enabled = false; //do this first, because gfx3d_execute3D() will cause more scheduled events if necessary + gfx3d_execute3D(); + MMU.gfx3dCycles = max(MMU.gfx3dCycles,nds_timer); //uhh i dont entirely understand why this was necessary + //i need to learn more about how the new gxfifo works, but I am leaving that to you for now crazymax ^_^ + #endif + } + + FORCEINLINE u64 next() + { + if(enabled) return MMU.gfx3dCycles; + else return kNever; + } +}; + +template struct TSequenceItem_Timer : public TSequenceItem +{ + FORCEINLINE bool isTriggered() + { + return enabled && nds_timer >= nds.timerCycle[procnum][num]; + } + + FORCEINLINE void schedule() + { + enabled = MMU.timerON[procnum][num] && MMU.timerMODE[procnum][num] != 0xFFFF; + } + + FORCEINLINE u64 next() + { + //todo - change this to go through an entire overflow cycle instead of a single increment + //however, in order to do this, we need to change the counter read emulation to calculate its value + //instead of just plucking the uptodate value (which would no longer be kept uptodate) + return nds.timerCycle[procnum][num]; + } + + FORCEINLINE void exec() + { + u64 timer = nds_timer; + u8* regs = procnum==0?ARM9Mem.ARM9_REG:MMU.ARM7_REG; + bool first = true, over; + //we'll need to check chained timers.. + for(int i=num;i<4;i++) + { + //maybe too many checks if this is here, but we need it here for now + if(!MMU.timerON[procnum][num]) return; + + if(MMU.timerMODE[procnum][num] == 0xFFFF) + { + ++(MMU.timer[procnum][num]); + over = !MMU.timer[procnum][num]; + } + else + { + if(!first) break; //this timer isn't chained. break the chain + first = false; + + over = true; + int remain = 65536 - MMU.timerReload[procnum][num]; + int ctr=0; + while(nds.timerCycle[procnum][num] <= nds_timer) { + nds.timerCycle[procnum][num] += (remain << MMU.timerMODE[procnum][num]); + ctr++; + } + if(ctr>1) { + printf("yikes!!!!! please report!\n"); + } + } + + if(over) + { + MMU.timer[procnum][num] = MMU.timerReload[procnum][num]; + if(T1ReadWord(regs, 0x102 + num*4) & 0x40) + { + if(procnum==0) NDS_makeARM9Int(3 + num); + else NDS_makeARM7Int(3 + num); + } + } + else + break; //no more chained timers to trigger. we're done here + } + } +}; + +template struct TSequenceItem_DMA : public TSequenceItem +{ + FORCEINLINE bool isTriggered() + { + return (MMU.DMAing[procnum][chan])&&nds_timer>=(MMU.DMACycle[procnum][chan]); + } + + FORCEINLINE u64 next() + { + if(!MMU.DMAing[procnum][chan]) return kNever; + return MMU.DMACycle[procnum][chan]; + } + + FORCEINLINE void exec() + { + u8* regs = procnum==0?ARM9Mem.ARM9_REG:MMU.ARM7_REG; + T1WriteLong(regs, 0xB8 + (0xC*chan), T1ReadLong(regs, 0xB8 + (0xC*chan)) & 0x7FFFFFFF); + if((MMU.DMACrt[procnum][chan])&(1<<30)) { + if(procnum==0) NDS_makeARM9Int(8+chan); + else NDS_makeARM7Int(8+chan); + } + MMU.DMAing[procnum][chan] = FALSE; + } +}; + +struct TSequenceItem_divider : public TSequenceItem +{ + FORCEINLINE bool isTriggered() + { + return MMU.divRunning && nds_timer >= MMU.divCycles; + } + + FORCEINLINE u64 next() + { + if(!MMU.divRunning) return kNever; + return MMU.divCycles; + } + + void exec() + { + T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2A0, (u32)MMU.divResult); + T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2A4, (u32)(MMU.divResult >> 32)); + T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2A8, (u32)MMU.divMod); + T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2AC, (u32)(MMU.divMod >> 32)); + T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x280, MMU.divCnt); + MMU.divRunning = FALSE; + } + +}; + +struct TSequenceItem_sqrtunit : public TSequenceItem +{ + FORCEINLINE bool isTriggered() + { + return MMU.sqrtRunning && nds_timer >= MMU.sqrtCycles; + } + + FORCEINLINE u64 next() + { + if(!MMU.sqrtRunning) return kNever; + return MMU.sqrtCycles; + } + + FORCEINLINE void exec() + { + T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2B4, MMU.sqrtResult); + T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2B0, MMU.sqrtCnt); + MMU.sqrtRunning = FALSE; + } + +}; + +struct Sequencer +{ + bool nds_vblankEnded; + bool reschedule; + TSequenceItem dispcnt; + TSequenceItem wifi; + TSequenceItem_divider divider; + TSequenceItem_sqrtunit sqrtunit; + TSequenceItem_GXFIFO gxfifo; + TSequenceItem_DMA<0,0> dma_0_0; TSequenceItem_DMA<0,1> dma_0_1; + TSequenceItem_DMA<0,2> dma_0_2; TSequenceItem_DMA<0,3> dma_0_3; + TSequenceItem_DMA<1,0> dma_1_0; TSequenceItem_DMA<1,1> dma_1_1; + TSequenceItem_DMA<1,2> dma_1_2; TSequenceItem_DMA<1,3> dma_1_3; + TSequenceItem_Timer<0,0> timer_0_0; TSequenceItem_Timer<0,1> timer_0_1; + TSequenceItem_Timer<0,2> timer_0_2; TSequenceItem_Timer<0,3> timer_0_3; + TSequenceItem_Timer<1,0> timer_1_0; TSequenceItem_Timer<1,1> timer_1_1; + TSequenceItem_Timer<1,2> timer_1_2; TSequenceItem_Timer<1,3> timer_1_3; + + void init(); + + void execHardware(); + u64 findNext(); + + void save(std::ostream* os) + { + write64le(nds_timer,os); + write64le(nds_arm9_timer,os); + write64le(nds_arm7_timer,os); + dispcnt.save(os); + divider.save(os); + sqrtunit.save(os); + gxfifo.save(os); +#define SAVE(I,X,Y) I##_##X##_##Y .save(os); + SAVE(timer,0,0); SAVE(timer,0,1); SAVE(timer,0,2); SAVE(timer,0,3); + SAVE(timer,1,0); SAVE(timer,1,1); SAVE(timer,1,2); SAVE(timer,1,3); + SAVE(dma,0,0); SAVE(dma,0,1); SAVE(dma,0,2); SAVE(dma,0,3); + SAVE(dma,1,0); SAVE(dma,1,1); SAVE(dma,1,2); SAVE(dma,1,3); +#undef SAVE + } + + bool load(std::istream* is) + { + if(read64le(&nds_timer,is) != 1) return false; + if(read64le(&nds_arm9_timer,is) != 1) return false; + if(read64le(&nds_arm7_timer,is) != 1) return false; + if(!dispcnt.load(is)) return false; + if(!divider.load(is)) return false; + if(!sqrtunit.load(is)) return false; + if(!gxfifo.load(is)) return false; +#define LOAD(I,X,Y) if(!I##_##X##_##Y .load(is)) return false; + LOAD(timer,0,0); LOAD(timer,0,1); LOAD(timer,0,2); LOAD(timer,0,3); + LOAD(timer,1,0); LOAD(timer,1,1); LOAD(timer,1,2); LOAD(timer,1,3); + LOAD(dma,0,0); LOAD(dma,0,1); LOAD(dma,0,2); LOAD(dma,0,3); + LOAD(dma,1,0); LOAD(dma,1,1); LOAD(dma,1,2); LOAD(dma,1,3); +#undef LOAD + + return true; + } + +} sequencer; + +void NDS_RescheduleGXFIFO() +{ +#ifdef USE_GEOMETRY_FIFO_EMULATION + sequencer.gxfifo.enabled = true; + NDS_Reschedule(); +#endif +} + +void NDS_RescheduleTimers() +{ +#define check(X,Y) sequencer.timer_##X##_##Y .schedule(); + check(0,0); check(0,1); check(0,2); check(0,3); + check(1,0); check(1,1); check(1,2); check(1,3); +#undef check + + NDS_Reschedule(); +} + +void NDS_RescheduleDMA() +{ + //TBD + NDS_Reschedule(); +} + +void initSchedule() +{ + sequencer.init(); + + //begin at the very end of the last scanline + //so that at t=0 we can increment to scanline=0 + nds.VCount = 262; + + sequencer.nds_vblankEnded = false; +} + + +// 2196372 ~= (ARM7_CLOCK << 16) / 1000000 +// This value makes more sense to me, because: +// ARM7_CLOCK = 33.51 mhz +// = 33513982 cycles per second +// = 33.513982 cycles per microsecond +const u64 kWifiCycles = 34*2; +//(this isn't very precise. I don't think it needs to be) + +void Sequencer::init() +{ + NDS_RescheduleTimers(); + NDS_RescheduleDMA(); + + reschedule = false; + nds_timer = 0; + nds_arm9_timer = 0; + nds_arm7_timer = 0; + + dispcnt.enabled = true; + dispcnt.param = ESI_DISPCNT_HStart; + dispcnt.timestamp = 0; + + gxfifo.enabled = false; + + + #ifdef EXPERIMENTAL_WIFI + wifi.enabled = true; + wifi.timestamp = kWifiCycles; + #else + wifi.enabled = false; + #endif +} + + +void execHardware_hblank() +{ + //turn on hblank status bit + T1WriteWord(ARM9Mem.ARM9_REG, 4, T1ReadWord(ARM9Mem.ARM9_REG, 4) | 2); + T1WriteWord(MMU.ARM7_REG, 4, T1ReadWord(MMU.ARM7_REG, 4) | 2); + + //fire hblank interrupts if necessary + NDS_ARM9HBlankInt(); + NDS_ARM7HBlankInt(); + + //emulation housekeeping. for some reason we always do this at hblank, + //even though it sounds more reasonable to do it at hstart + SPU_Emulate_core(); + driver->AVI_SoundUpdate(SPU_core->outbuf,spu_core_samples); + WAV_WavSoundUpdate(SPU_core->outbuf,spu_core_samples); + + //this logic was formerly at hblank time. it was moved to the beginning of the scanline on a whim + if(nds.VCount<192) + { + //trigger hblank dmas. + //but should this happen for non-displayed scanlines??? not sure + execHardware_doAllDma(EDMAMode_HBlank); + } +} + +void execHardware_hstart_vblankEnd() +{ + nds.VCount = 0; + sequencer.nds_vblankEnded = true; + sequencer.reschedule = true; + + //turn off vblank status bit + T1WriteWord(ARM9Mem.ARM9_REG, 4, T1ReadWord(ARM9Mem.ARM9_REG, 4) & 0xFFFE); + T1WriteWord(MMU.ARM7_REG, 4, T1ReadWord(MMU.ARM7_REG, 4) & 0xFFFE); +} + +void execHardware_hstart_vblankStart() +{ + //turn on vblank status bit + T1WriteWord(ARM9Mem.ARM9_REG, 4, T1ReadWord(ARM9Mem.ARM9_REG, 4) | 1); + T1WriteWord(MMU.ARM7_REG, 4, T1ReadWord(MMU.ARM7_REG, 4) | 1); + + //fire vblank interrupts if necessary + NDS_ARM9VBlankInt(); + NDS_ARM7VBlankInt(); + + //some emulation housekeeping + gfx3d_VBlankSignal(); + if(SkipNext2DFrame) + { + SkipCur2DFrame = true; + SkipNext2DFrame = false; + } + else + SkipCur2DFrame = false; + + //trigger vblank dmas + execHardware_doAllDma(EDMAMode_VBlank); +} + +void execHardware_hstart_vcount() +{ + u16 vmatch = T1ReadWord(ARM9Mem.ARM9_REG, 4); + if(nds.VCount==((vmatch>>8)|((vmatch<<1)&(1<<8)))) + { + T1WriteWord(ARM9Mem.ARM9_REG, 4, T1ReadWord(ARM9Mem.ARM9_REG, 4) | 4); + if(T1ReadWord(ARM9Mem.ARM9_REG, 4) & 32) + NDS_makeARM9Int(2); + } + else + T1WriteWord(ARM9Mem.ARM9_REG, 4, T1ReadWord(ARM9Mem.ARM9_REG, 4) & 0xFFFB); + + vmatch = T1ReadWord(MMU.ARM7_REG, 4); + if(nds.VCount==((vmatch>>8)|((vmatch<<1)&(1<<8)))) + { + T1WriteWord(MMU.ARM7_REG, 4, T1ReadWord(MMU.ARM7_REG, 4) | 4); + if(T1ReadWord(MMU.ARM7_REG, 4) & 32) + NDS_makeARM7Int(2); + } + else + T1WriteWord(MMU.ARM7_REG, 4, T1ReadWord(MMU.ARM7_REG, 4) & 0xFFFB); +} + +void execHardware_hstart() +{ + nds.VCount++; + + if(nds.VCount==263) + { + execHardware_hstart_vblankEnd(); + } else if(nds.VCount==192) + { + execHardware_hstart_vblankStart(); + } + + //write the new vcount + T1WriteWord(ARM9Mem.ARM9_REG, 6, nds.VCount); + T1WriteWord(ARM9Mem.ARM9_REG, 0x1006, nds.VCount); + T1WriteWord(MMU.ARM7_REG, 6, nds.VCount); + T1WriteWord(MMU.ARM7_REG, 0x1006, nds.VCount); + + //turn off hblank status bit + T1WriteWord(ARM9Mem.ARM9_REG, 4, T1ReadWord(ARM9Mem.ARM9_REG, 4) & 0xFFFD); + T1WriteWord(MMU.ARM7_REG, 4, T1ReadWord(MMU.ARM7_REG, 4) & 0xFFFD); + + //handle vcount status + execHardware_hstart_vcount(); + + //this logic was formerly at hblank time. it was moved to the beginning of the scanline on a whim + if(nds.VCount<192) + { + //trigger hstart dmas + //in an effort to more accurately mimic what might happen in cases where these are used + //to adjust the scanline which is just about to render, the dma occurs before the scanline draw + execHardware_doAllDma(EDMAMode_HStart); + + //this is hacky. + //there is a corresponding hack in doDMA + execHardware_doAllDma(EDMAMode_MemDisplay); + + if(!SkipCur2DFrame) + { + GPU_ligne(&MainScreen, nds.VCount); + GPU_ligne(&SubScreen, nds.VCount); + } + } + + //end of 3d vblank + if(nds.VCount==214) + { + gfx3d_VBlankEndSignal(SkipCur3DFrame); + SkipCur3DFrame = false; + } +} + +void NDS_Reschedule() +{ + sequencer.reschedule = true; +} + +u64 Sequencer::findNext() +{ + u64 next = kNever; + next = min(next,dispcnt.next()); + next = min(next,divider.next()); + next = min(next,sqrtunit.next()); + next = min(next,gxfifo.next()); + +#ifdef EXPERIMENTAL_WIFI + next = min(next,wifi.next()); +#endif + +#define test(X,Y) next = min(next,dma_##X##_##Y .next()); + test(0,0); test(0,1); test(0,2); test(0,3); + test(1,0); test(1,1); test(1,2); test(1,3); +#undef test +#define test(X,Y) if(timer_##X##_##Y .enabled) next = min(next,timer_##X##_##Y .next()); + test(0,0); test(0,1); test(0,2); test(0,3); + test(1,0); test(1,1); test(1,2); test(1,3); +#undef test + + return next; +} + +void Sequencer::execHardware() +{ + if(dispcnt.isTriggered()) + { + switch(dispcnt.param) + { + case ESI_DISPCNT_HStart: + execHardware_hstart(); + dispcnt.timestamp += 3168; + dispcnt.param = ESI_DISPCNT_HBlank; + break; + case ESI_DISPCNT_HBlank: + execHardware_hblank(); + dispcnt.timestamp += 1092; + dispcnt.param = ESI_DISPCNT_HStart; + break; + } + } + +#ifdef EXPERIMENTAL_WIFI + if(wifi.isTriggered()) + { + WIFI_usTrigger(&wifiMac); + WIFI_SoftAP_usTrigger(&wifiMac); + wifi.timestamp += kWifiCycles; + } +#endif + + if(divider.isTriggered()) divider.exec(); + if(sqrtunit.isTriggered()) sqrtunit.exec(); + if(gxfifo.isTriggered()) gxfifo.exec(); + + +#define test(X,Y) if(dma_##X##_##Y .isTriggered()) dma_##X##_##Y .exec(); + test(0,0); test(0,1); test(0,2); test(0,3); + test(1,0); test(1,1); test(1,2); test(1,3); +#undef test +#define test(X,Y) if(timer_##X##_##Y .enabled) if(timer_##X##_##Y .isTriggered()) timer_##X##_##Y .exec(); + test(0,0); test(0,1); test(0,2); test(0,3); + test(1,0); test(1,1); test(1,2); test(1,3); +#undef test +} + +void execHardware_interrupts(); + +void nds_savestate(std::ostream* os) +{ + //version + write32le(0,os); + + sequencer.save(os); +} + +bool nds_loadstate(std::istream* is, int size) +{ + //read version + int version; + if(read32le(&version,is) != 1) return false; + + if(version != 0) return false; + + return sequencer.load(is); +} + +//#define LOG_ARM9 +//#define LOG_ARM7 +//static bool dolog = false; + +FORCEINLINE void arm9log() +{ +#ifdef LOG_ARM9 + if(dolog) + { + char dasmbuf[1024]; + char logbuf[4096]; + if(NDS_ARM9.CPSR.bits.T) + des_thumb_instructions_set[((NDS_ARM9.instruction)>>6)&1023](NDS_ARM9.instruct_adr, NDS_ARM9.instruction, dasmbuf); + else + des_arm_instructions_set[INDEX(NDS_ARM9.instruction)](NDS_ARM9.instruct_adr, NDS_ARM9.instruction, dasmbuf); + + printf("%05d %ll12d 9:%08X %08X %-30s R00:%08X R01:%08X R02:%08X R03:%08X R04:%08X R05:%08X R06:%08X R07:%08X R08:%08X R09:%08X R10:%08X R11:%08X R12:%08X R13:%08X R14:%08X R15:%08X\n", + currFrameCounter, nds_timer, + NDS_ARM9.instruct_adr,NDS_ARM9.instruction, dasmbuf, + NDS_ARM9.R[0], NDS_ARM9.R[1], NDS_ARM9.R[2], NDS_ARM9.R[3], NDS_ARM9.R[4], NDS_ARM9.R[5], NDS_ARM9.R[6], NDS_ARM9.R[7], + NDS_ARM9.R[8], NDS_ARM9.R[9], NDS_ARM9.R[10], NDS_ARM9.R[11], NDS_ARM9.R[12], NDS_ARM9.R[13], NDS_ARM9.R[14], NDS_ARM9.R[15]); + } +#endif +} + +FORCEINLINE void arm7log() +{ + #ifdef LOG_ARM7 + if(dolog) + { + char dasmbuf[1024]; + if(NDS_ARM7.CPSR.bits.T) + des_thumb_instructions_set[((NDS_ARM7.instruction)>>6)&1023](NDS_ARM7.instruct_adr, NDS_ARM7.instruction, dasmbuf); + else + des_arm_instructions_set[INDEX(NDS_ARM7.instruction)](NDS_ARM7.instruct_adr, NDS_ARM7.instruction, dasmbuf); + printf("%05d %ll12d 7:%08X %08X %-30s R00:%08X R01:%08X R02:%08X R03:%08X R04:%08X R05:%08X R06:%08X R07:%08X R08:%08X R09:%08X R10:%08X R11:%08X R12:%08X R13:%08X R14:%08X R15:%08X\n", + currFrameCounter, nds_timer, + NDS_ARM7.instruct_adr,NDS_ARM7.instruction, dasmbuf, + NDS_ARM7.R[0], NDS_ARM7.R[1], NDS_ARM7.R[2], NDS_ARM7.R[3], NDS_ARM7.R[4], NDS_ARM7.R[5], NDS_ARM7.R[6], NDS_ARM7.R[7], + NDS_ARM7.R[8], NDS_ARM7.R[9], NDS_ARM7.R[10], NDS_ARM7.R[11], NDS_ARM7.R[12], NDS_ARM7.R[13], NDS_ARM7.R[14], NDS_ARM7.R[15], + NDS_ARM7.CPSR, NDS_ARM7.SPSR); + } + #endif +} template void NDS_exec(s32 nb) { + //TODO - singlestep is broken + int i, j; LagFrameFlag=1; @@ -1628,869 +2066,77 @@ void NDS_exec(s32 nb) if((currFrameCounter&63) == 0) MMU_new.backupDevice.lazy_flush(); - //increase this to execute more instructions in each batch (reducing overhead) - //the value of 4 seems to optimize speed.. do lower values increase precision? - //answer: YES, MAYBE. and after 0.9.3 we need to study it (spider-man) - const int INSTRUCTIONS_PER_BATCH = 4; + sequencer.nds_vblankEnded = false; - //decreasing this should increase precision at the cost of speed - //the traditional value was somewhere between 100 and 400 depending on circumstances - const int CYCLES_TO_WAIT_FOR_IRQ = 400; + //these have not been tuned very well yet. + const int kMaxWork = 4000; + const int kIrqWait = 4000; - for(; (nb >= nds.cycles) && ((FORCE)||(execute)); ) + if(nds.sleeping) { - for (j = 0; j < INSTRUCTIONS_PER_BATCH && (!FORCE) && (execute); j++) + gpu_UpdateRender(); + if((MMU.reg_IE[1] & MMU.reg_IF[1]) & (1<<22)) { - if(nds.ARM9Cycle<=nds.cycles) - { - for (i = 0; i < INSTRUCTIONS_PER_BATCH && (!FORCE) && (execute); i++) - { - if(nds.sleeping) { - break; - } else - if(NDS_ARM9.waitIRQ) { - nds.ARM9Cycle += CYCLES_TO_WAIT_FOR_IRQ; - nds.idleCycles += CYCLES_TO_WAIT_FOR_IRQ; - break; //it is rather pointless to do this more than once - } else { - #ifdef LOG_ARM9 - if(dolog) - { - char dasmbuf[1024]; - char logbuf[4096]; - if(NDS_ARM9.CPSR.bits.T) - des_thumb_instructions_set[((NDS_ARM9.instruction)>>6)&1023](NDS_ARM9.instruct_adr, NDS_ARM9.instruction, dasmbuf); - else - des_arm_instructions_set[INDEX(NDS_ARM9.instruction)](NDS_ARM9.instruct_adr, NDS_ARM9.instruction, dasmbuf); - - printf("%05d %08d 9:%08X %08X %-30s R00:%08X R01:%08X R02:%08X R03:%08X R04:%08X R05:%08X R06:%08X R07:%08X R08:%08X R09:%08X R10:%08X R11:%08X R12:%08X R13:%08X R14:%08X R15:%08X\n", - currFrameCounter, nds.cycles, - NDS_ARM9.instruct_adr,NDS_ARM9.instruction, dasmbuf, - NDS_ARM9.R[0], NDS_ARM9.R[1], NDS_ARM9.R[2], NDS_ARM9.R[3], NDS_ARM9.R[4], NDS_ARM9.R[5], NDS_ARM9.R[6], NDS_ARM9.R[7], - NDS_ARM9.R[8], NDS_ARM9.R[9], NDS_ARM9.R[10], NDS_ARM9.R[11], NDS_ARM9.R[12], NDS_ARM9.R[13], NDS_ARM9.R[14], NDS_ARM9.R[15]); - } - #endif - - bool r7zero = NDS_ARM9.R[7] == 0; - nds.ARM9Cycle += armcpu_exec(); - bool r7one = NDS_ARM9.R[7] == 1; - } - } -#ifdef _WIN32 -#ifdef DEVELOPER - DisassemblerTools_Refresh(); -#endif -#endif - } - -#ifdef EXPERIMENTAL_WIFI -#if 0 - - if((nds.ARM7Cycle % 0x3F03) == 0) - { - /* 3F03 arm7 cycles = ~1usec */ - // WRONG!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - // 1 usec = ~33 ARM7 cycles because ARM7 runs at 33.51 mhz - // 33.51 mhz = 33.51 million cycles per second = 33.51 cycles per usec - WIFI_usTrigger(&wifiMac) ; - } -#endif - - int nds7old = nds.ARM7Cycle; -#endif - - if(nds.ARM7Cycle<=nds.cycles) - { - for (i = 0; i < INSTRUCTIONS_PER_BATCH && (!FORCE) && (execute); i++) - { - if(nds.sleeping) { - break; - } else - if(NDS_ARM7.waitIRQ) - { - nds.ARM7Cycle += CYCLES_TO_WAIT_FOR_IRQ; - break; //it is rather pointless to do this more than once - } - else - { - #ifdef LOG_ARM7 - if(dolog) - { - char dasmbuf[1024]; - if(NDS_ARM7.CPSR.bits.T) - des_thumb_instructions_set[((NDS_ARM7.instruction)>>6)&1023](NDS_ARM7.instruct_adr, NDS_ARM7.instruction, dasmbuf); - else - des_arm_instructions_set[INDEX(NDS_ARM7.instruction)](NDS_ARM7.instruct_adr, NDS_ARM7.instruction, dasmbuf); - printf("%05d %08d 7:%08X %08X %-30s R00:%08X R01:%08X R02:%08X R03:%08X R04:%08X R05:%08X R06:%08X R07:%08X R08:%08X R09:%08X R10:%08X R11:%08X R12:%08X R13:%08X R14:%08X R15:%08X\n", - currFrameCounter, nds.cycles, - NDS_ARM7.instruct_adr,NDS_ARM7.instruction, dasmbuf, - NDS_ARM7.R[0], NDS_ARM7.R[1], NDS_ARM7.R[2], NDS_ARM7.R[3], NDS_ARM7.R[4], NDS_ARM7.R[5], NDS_ARM7.R[6], NDS_ARM7.R[7], - NDS_ARM7.R[8], NDS_ARM7.R[9], NDS_ARM7.R[10], NDS_ARM7.R[11], NDS_ARM7.R[12], NDS_ARM7.R[13], NDS_ARM7.R[14], NDS_ARM7.R[15], - NDS_ARM7.CPSR, NDS_ARM7.SPSR); - } - #endif - nds.ARM7Cycle += (armcpu_exec()<<1); - } - } -#ifdef _WIN32 -#ifdef DEVELOPER - DisassemblerTools_Refresh(); -#endif -#endif - } - -//this doesnt work anyway. why take a speed hit for public releases? -// Luigi__: I don't agree. We should start include wifi emulation in public releases -// because it already allows games to not hang during wifi operations -// and thus games that perform wifi checks upon boot shouldn't hang with wifi -// emulation turned on. -#ifndef PUBLIC_RELEASE -#ifdef EXPERIMENTAL_WIFI - // FIXME: the wifi stuff isn't actually clocked by the ARM7 clock, - // but by a 22 mhz oscillator. - // But do we really care? while we're triggering wifi core every microsecond, - // everything is fine, isn't it? - - //zeromus way: i did this in a rush and it is not perfect, but it is more like what it needs to be - //nds.wifiCycle += (nds.ARM7Cycle-nds7old)<<16; - //while(nds.wifiCycle > 0) - //{ - // nds.wifiCycle -= 946453; //22*22000000*65536/ARM7_CLOCK; - // WIFI_usTrigger(&wifiMac); - // WIFI_SoftAP_usTrigger(&wifiMac); - //} - // - //luigi's way> - // new one, more like zeromus way - // but I can't understand why it uses that value (22*22000000*65536/ARM7_CLOCK) - nds.wifiCycle += (nds.ARM7Cycle - nds7old) << 16; - while (nds.wifiCycle > 0) - { - // 2196372 ~= (ARM7_CLOCK << 16) / 1000000 - // This value makes more sense to me, because: - // ARM7_CLOCK = 33.51 mhz - // = 33513982 cycles per second - // = 33.513982 cycles per microsecond - // The value is left shifted by 16 for more precision. - nds.wifiCycle -= (2196372 << 1); - - WIFI_usTrigger(&wifiMac); - WIFI_SoftAP_usTrigger(&wifiMac); - } -#endif -#endif - } // for (j = 0; j < INSTRUCTIONS_PER_BATCH && (!FORCE) && (execute); j++) - - if(!nds.sleeping) - { - - // for(i = 0; i < INSTRUCTIONS_PER_BATCH && (!FORCE) && (execute); i++) - // { - - nds.cycles = std::min(nds.ARM9Cycle,nds.ARM7Cycle); - - //debug(); - - if(nds.cycles>=nds.nextHBlank) - { - if(!nds.lignerendu) - { - T1WriteWord(ARM9Mem.ARM9_REG, 4, T1ReadWord(ARM9Mem.ARM9_REG, 4) | 2); - T1WriteWord(MMU.ARM7_REG, 4, T1ReadWord(MMU.ARM7_REG, 4) | 2); - NDS_ARM9HBlankInt(); - NDS_ARM7HBlankInt(); - SPU_Emulate_core(); - driver->AVI_SoundUpdate(SPU_core->outbuf,spu_core_samples); - WAV_WavSoundUpdate(SPU_core->outbuf,spu_core_samples); - if(nds.VCount<192) - { - if(!SkipCur2DFrame) - { - GPU_ligne(&MainScreen, nds.VCount); - GPU_ligne(&SubScreen, nds.VCount); - } - - if(MMU.DMAStartTime[0][0] == 2) - MMU_doDMA(0); - if(MMU.DMAStartTime[0][1] == 2) - MMU_doDMA(1); - if(MMU.DMAStartTime[0][2] == 2) - MMU_doDMA(2); - if(MMU.DMAStartTime[0][3] == 2) - MMU_doDMA(3); - } - nds.lignerendu = TRUE; - } - if(nds.cycles>=nds.nextHBlank+1092) - { - u32 vmatch; - - ++nds.VCount; - nds.nextHBlank += 4260; - T1WriteWord(ARM9Mem.ARM9_REG, 4, T1ReadWord(ARM9Mem.ARM9_REG, 4) & 0xFFFD); - T1WriteWord(MMU.ARM7_REG, 4, T1ReadWord(MMU.ARM7_REG, 4) & 0xFFFD); - - if(MMU.DMAStartTime[0][0] == 3) - MMU_doDMA(0); - if(MMU.DMAStartTime[0][1] == 3) - MMU_doDMA(1); - if(MMU.DMAStartTime[0][2] == 3) - MMU_doDMA(2); - if(MMU.DMAStartTime[0][3] == 3) - MMU_doDMA(3); - - // Main memory display - if(MMU.DMAStartTime[0][0] == 4) - { - MMU_doDMA(0); - MMU.DMAStartTime[0][0] = 0; - } - if(MMU.DMAStartTime[0][1] == 4) - { - MMU_doDMA(1); - MMU.DMAStartTime[0][1] = 0; - } - if(MMU.DMAStartTime[0][2] == 4) - { - MMU_doDMA(2); - MMU.DMAStartTime[0][2] = 0; - } - if(MMU.DMAStartTime[0][3] == 4) - { - MMU_doDMA(3); - MMU.DMAStartTime[0][3] = 0; - } - - if(MMU.DMAStartTime[1][0] == 4) - { - MMU_doDMA(0); - MMU.DMAStartTime[1][0] = 0; - } - if(MMU.DMAStartTime[1][1] == 4) - { - MMU_doDMA(1); - MMU.DMAStartTime[0][1] = 0; - } - if(MMU.DMAStartTime[1][2] == 4) - { - MMU_doDMA(2); - MMU.DMAStartTime[1][2] = 0; - } - if(MMU.DMAStartTime[1][3] == 4) - { - MMU_doDMA(3); - MMU.DMAStartTime[1][3] = 0; - } - - nds.lignerendu = FALSE; - if(nds.VCount==192) - { - //osdA->update(); - gfx3d_VBlankSignal(); - - if(SkipNext2DFrame) - { - SkipCur2DFrame = true; - SkipNext2DFrame = false; - } - else - SkipCur2DFrame = false; - - T1WriteWord(ARM9Mem.ARM9_REG, 4, T1ReadWord(ARM9Mem.ARM9_REG, 4) | 1); - T1WriteWord(MMU.ARM7_REG, 4, T1ReadWord(MMU.ARM7_REG, 4) | 1); - NDS_ARM9VBlankInt(); - NDS_ARM7VBlankInt(); - - nds.runCycleCollector[nds.idleFrameCounter] = 1120380-nds.idleCycles; - nds.idleFrameCounter++; - nds.idleFrameCounter &= 15; - nds.idleCycles = 0; - - - if(MMU.DMAStartTime[0][0] == 1) - MMU_doDMA(0); - if(MMU.DMAStartTime[0][1] == 1) - MMU_doDMA(1); - if(MMU.DMAStartTime[0][2] == 1) - MMU_doDMA(2); - if(MMU.DMAStartTime[0][3] == 1) - MMU_doDMA(3); - - if(MMU.DMAStartTime[1][0] == 1) - MMU_doDMA(0); - if(MMU.DMAStartTime[1][1] == 1) - MMU_doDMA(1); - if(MMU.DMAStartTime[1][2] == 1) - MMU_doDMA(2); - if(MMU.DMAStartTime[1][3] == 1) - MMU_doDMA(3); - } - else if(nds.VCount==214) - { - gfx3d_VBlankEndSignal(SkipCur3DFrame); - SkipCur3DFrame = false; - } - else if(nds.VCount==263) - { - //osd->update(); - //osdB->update(); - gpu_UpdateRender(); - - nds.nextHBlank = 3168; - nds.VCount = 0; - T1WriteWord(ARM9Mem.ARM9_REG, 4, T1ReadWord(ARM9Mem.ARM9_REG, 4) & 0xFFFE); - T1WriteWord(MMU.ARM7_REG, 4, T1ReadWord(MMU.ARM7_REG, 4) & 0xFFFE); - - nds.cycles -= (560190<<1); - nds.ARM9Cycle -= (560190<<1); - nds.ARM7Cycle -= (560190<<1); - nb -= (560190<<1); - -#ifdef USE_GEOMETRY_FIFO_EMULATION - MMU.gfx3dCycles -= (560190 << 1); -#endif - - if(MMU.divRunning) - { - MMU.divCycles -= (560190 << 1); - } - - if(MMU.sqrtRunning) - { - MMU.sqrtCycles -= (560190 << 1); - } - - if (MMU.CheckTimers) - { - if(MMU.timerON[0][0]) nds.timerCycle[0][0] -= (560190<<1); - if(MMU.timerON[0][1]) nds.timerCycle[0][1] -= (560190<<1); - if(MMU.timerON[0][2]) nds.timerCycle[0][2] -= (560190<<1); - if(MMU.timerON[0][3]) nds.timerCycle[0][3] -= (560190<<1); - - if(MMU.timerON[1][0]) nds.timerCycle[1][0] -= (560190<<1); - if(MMU.timerON[1][1]) nds.timerCycle[1][1] -= (560190<<1); - if(MMU.timerON[1][2]) nds.timerCycle[1][2] -= (560190<<1); - if(MMU.timerON[1][3]) nds.timerCycle[1][3] -= (560190<<1); - } - - if (MMU.CheckDMAs) - { - if(MMU.DMAing[0][0]) MMU.DMACycle[0][0] -= (560190<<1); - if(MMU.DMAing[0][1]) MMU.DMACycle[0][1] -= (560190<<1); - if(MMU.DMAing[0][2]) MMU.DMACycle[0][2] -= (560190<<1); - if(MMU.DMAing[0][3]) MMU.DMACycle[0][3] -= (560190<<1); - - if(MMU.DMAing[1][0]) MMU.DMACycle[1][0] -= (560190<<1); - if(MMU.DMAing[1][1]) MMU.DMACycle[1][1] -= (560190<<1); - if(MMU.DMAing[1][2]) MMU.DMACycle[1][2] -= (560190<<1); - if(MMU.DMAing[1][3]) MMU.DMACycle[1][3] -= (560190<<1); - } - } - - T1WriteWord(ARM9Mem.ARM9_REG, 6, nds.VCount); - T1WriteWord(ARM9Mem.ARM9_REG, 0x1006, nds.VCount); - T1WriteWord(MMU.ARM7_REG, 6, nds.VCount); - T1WriteWord(MMU.ARM7_REG, 0x1006, nds.VCount); - - vmatch = T1ReadWord(ARM9Mem.ARM9_REG, 4); - if(nds.VCount==((vmatch>>8)|((vmatch<<1)&(1<<8)))) - { - T1WriteWord(ARM9Mem.ARM9_REG, 4, T1ReadWord(ARM9Mem.ARM9_REG, 4) | 4); - if(T1ReadWord(ARM9Mem.ARM9_REG, 4) & 32) - NDS_makeARM9Int(2); - } - else - T1WriteWord(ARM9Mem.ARM9_REG, 4, T1ReadWord(ARM9Mem.ARM9_REG, 4) & 0xFFFB); - - vmatch = T1ReadWord(MMU.ARM7_REG, 4); - if(nds.VCount==((vmatch>>8)|((vmatch<<1)&(1<<8)))) - { - T1WriteWord(MMU.ARM7_REG, 4, T1ReadWord(MMU.ARM7_REG, 4) | 4); - if(T1ReadWord(MMU.ARM7_REG, 4) & 32) - NDS_makeARM7Int(2); - } - else - T1WriteWord(MMU.ARM7_REG, 4, T1ReadWord(MMU.ARM7_REG, 4) & 0xFFFB); - } - } // if(nds.cycles >= nds.nextHBlank) - - /* } // for(i = 0; i < INSTRUCTIONS_PER_BATCH && (!FORCE) && (execute); i++) - - } // if(!nds.sleeping) - - } // for (j = 0; j < INSTRUCTIONS_PER_BATCH && (!FORCE) && (execute); j++) - - if(!nds.sleeping) - {*/ - -#ifdef USE_GEOMETRY_FIFO_EMULATION - if (nds.cycles > MMU.gfx3dCycles) - gfx3d_execute3D(); -#endif - - if(MMU.divRunning) - { - if(nds.cycles > MMU.divCycles) - { - T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2A0, (u32)MMU.divResult); - T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2A4, (u32)(MMU.divResult >> 32)); - T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2A8, (u32)MMU.divMod); - T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2AC, (u32)(MMU.divMod >> 32)); - T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x280, MMU.divCnt); - - MMU.divRunning = FALSE; - } + nds.sleeping = FALSE; } - - if(MMU.sqrtRunning) + } + else + { + for(;;) { - if(nds.cycles > MMU.sqrtCycles) - { - T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2B4, MMU.sqrtResult); - T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2B0, MMU.sqrtCnt); + sequencer.execHardware(); - MMU.sqrtRunning = FALSE; - } - } + //break out once per frame + if(sequencer.nds_vblankEnded) break; + //it should be benign to execute execHardware in the next frame, + //since there won't be anything for it to do (everything should be scheduled in the future) - if (MMU.CheckTimers) - { - /* assume the timers have not expired */ - nds.timerOver[0][0] = 0; - nds.timerOver[0][1] = 0; - nds.timerOver[0][2] = 0; - nds.timerOver[0][3] = 0; - nds.timerOver[1][0] = 0; - nds.timerOver[1][1] = 0; - nds.timerOver[1][2] = 0; - nds.timerOver[1][3] = 0; - if(MMU.timerON[0][0]) + execHardware_interrupts(); + + //find next work unit: + u64 next = sequencer.findNext(); + next = min(next,nds_timer+kMaxWork); //lets set an upper limit for now + + //printf("%d\n",(next-nds_timer)); + + sequencer.reschedule = false; + + while(nds_timer>MMU.timerMODE[0][0]; - nds.old = MMU.timer[0][0]; - MMU.timer[0][0] += nds.diff; - nds.timerCycle[0][0] += (nds.diff << MMU.timerMODE[0][0]); - nds.timerOver[0][0] = nds.old>MMU.timer[0][0]; - if(nds.timerOver[0][0]) - { - if(T1ReadWord(ARM9Mem.ARM9_REG, 0x102) & 0x40) - NDS_makeARM9Int(3); - MMU.timer[0][0] = MMU.timerReload[0][0]; - } - } - break; + if(NDS_ARM9.waitIRQ) nds_arm9_timer = min(next,nds_arm9_timer + kIrqWait); + else { + arm9log(); + nds_arm9_timer += armcpu_exec(); + } + + } + if(nds_arm7_timer<=nds_timer) + { + if(NDS_ARM7.waitIRQ) + nds_arm7_timer = min(next,nds_arm7_timer + kIrqWait); + else { + arm7log(); + nds_arm7_timer += (armcpu_exec()<<1); } } - else - { - MMU.timerRUN[0][0] = TRUE; - nds.timerCycle[0][0] = nds.cycles; - } - } - if(MMU.timerON[0][1]) - { - if(MMU.timerRUN[0][1]) - { - switch(MMU.timerMODE[0][1]) - { - case 0xFFFF : - if(nds.timerOver[0][0]) - { - ++(MMU.timer[0][1]); - nds.timerOver[0][1] = !MMU.timer[0][1]; - if (nds.timerOver[0][1]) - { - if(T1ReadWord(ARM9Mem.ARM9_REG, 0x106) & 0x40) - NDS_makeARM9Int(4); - MMU.timer[0][1] = MMU.timerReload[0][1]; - } - } - break; - default : - { - nds.diff = (nds.cycles - nds.timerCycle[0][1])>>MMU.timerMODE[0][1]; - nds.old = MMU.timer[0][1]; - MMU.timer[0][1] += nds.diff; - nds.timerCycle[0][1] += nds.diff << MMU.timerMODE[0][1]; - nds.timerOver[0][1] = nds.old>MMU.timer[0][1]; - if(nds.timerOver[0][1]) - { - if(T1ReadWord(ARM9Mem.ARM9_REG, 0x106) & 0x40) - NDS_makeARM9Int(4); - MMU.timer[0][1] = MMU.timerReload[0][1]; - } - } - break; - } - } - else - { - MMU.timerRUN[0][1] = TRUE; - nds.timerCycle[0][1] = nds.cycles; - } - } - if(MMU.timerON[0][2]) - { - if(MMU.timerRUN[0][2]) - { - switch(MMU.timerMODE[0][2]) - { - case 0xFFFF : - if(nds.timerOver[0][1]) - { - ++(MMU.timer[0][2]); - nds.timerOver[0][2] = !MMU.timer[0][2]; - if (nds.timerOver[0][2]) - { - if(T1ReadWord(ARM9Mem.ARM9_REG, 0x10A) & 0x40) - NDS_makeARM9Int(5); - MMU.timer[0][2] = MMU.timerReload[0][2]; - } - } - break; - default : - { - nds.diff = (nds.cycles - nds.timerCycle[0][2])>>MMU.timerMODE[0][2]; - nds.old = MMU.timer[0][2]; - MMU.timer[0][2] += nds.diff; - nds.timerCycle[0][2] += nds.diff << MMU.timerMODE[0][2]; - nds.timerOver[0][2] = nds.old>MMU.timer[0][2]; - if(nds.timerOver[0][2]) - { - if(T1ReadWord(ARM9Mem.ARM9_REG, 0x10A) & 0x40) - NDS_makeARM9Int(5); - MMU.timer[0][2] = MMU.timerReload[0][2]; - } - } - break; - } - } - else - { - MMU.timerRUN[0][2] = TRUE; - nds.timerCycle[0][2] = nds.cycles; - } - } - if(MMU.timerON[0][3]) - { - if(MMU.timerRUN[0][3]) - { - switch(MMU.timerMODE[0][3]) - { - case 0xFFFF : - if(nds.timerOver[0][2]) - { - ++(MMU.timer[0][3]); - nds.timerOver[0][3] = !MMU.timer[0][3]; - if (nds.timerOver[0][3]) - { - if(T1ReadWord(ARM9Mem.ARM9_REG, 0x10E) & 0x40) - NDS_makeARM9Int(6); - MMU.timer[0][3] = MMU.timerReload[0][3]; - } - } - break; - default : - { - nds.diff = (nds.cycles - nds.timerCycle[0][3])>>MMU.timerMODE[0][3]; - nds.old = MMU.timer[0][3]; - MMU.timer[0][3] += nds.diff; - nds.timerCycle[0][3] += nds.diff << MMU.timerMODE[0][3]; - nds.timerOver[0][3] = nds.old>MMU.timer[0][3]; - if(nds.timerOver[0][3]) - { - if(T1ReadWord(ARM9Mem.ARM9_REG, 0x10E) & 0x40) - NDS_makeARM9Int(6); - MMU.timer[0][3] = MMU.timerReload[0][3]; - } - } - break; - } - } - else - { - MMU.timerRUN[0][3] = TRUE; - nds.timerCycle[0][3] = nds.cycles; - } + nds_timer = min(nds_arm7_timer,nds_arm9_timer); } - if(MMU.timerON[1][0]) - { - if(MMU.timerRUN[1][0]) - { - switch(MMU.timerMODE[1][0]) - { - case 0xFFFF : - break; - default : - { - nds.diff = (nds.cycles - nds.timerCycle[1][0])>>MMU.timerMODE[1][0]; - nds.old = MMU.timer[1][0]; - MMU.timer[1][0] += nds.diff; - nds.timerCycle[1][0] += nds.diff << MMU.timerMODE[1][0]; - nds.timerOver[1][0] = nds.old>MMU.timer[1][0]; - if(nds.timerOver[1][0]) - { - if(T1ReadWord(MMU.ARM7_REG, 0x102) & 0x40) - NDS_makeARM7Int(3); - MMU.timer[1][0] = MMU.timerReload[1][0]; - } - } - break; - } - } - else - { - MMU.timerRUN[1][0] = TRUE; - nds.timerCycle[1][0] = nds.cycles; - } - } - if(MMU.timerON[1][1]) - { - if(MMU.timerRUN[1][1]) - { - switch(MMU.timerMODE[1][1]) - { - case 0xFFFF : - if(nds.timerOver[1][0]) - { - ++(MMU.timer[1][1]); - nds.timerOver[1][1] = !MMU.timer[1][1]; - if (nds.timerOver[1][1]) - { - if(T1ReadWord(MMU.ARM7_REG, 0x106) & 0x40) - NDS_makeARM7Int(4); - MMU.timer[1][1] = MMU.timerReload[1][1]; - } - } - break; - default : - { - nds.diff = (nds.cycles - nds.timerCycle[1][1])>>MMU.timerMODE[1][1]; - nds.old = MMU.timer[1][1]; - MMU.timer[1][1] += nds.diff; - nds.timerCycle[1][1] += nds.diff << MMU.timerMODE[1][1]; - nds.timerOver[1][1] = nds.old>MMU.timer[1][1]; - if(nds.timerOver[1][1]) - { - if(T1ReadWord(MMU.ARM7_REG, 0x106) & 0x40) - NDS_makeARM7Int(4); - MMU.timer[1][1] = MMU.timerReload[1][1]; - } - } - break; - } - } - else - { - MMU.timerRUN[1][1] = TRUE; - nds.timerCycle[1][1] = nds.cycles; - } - } - if(MMU.timerON[1][2]) - { - if(MMU.timerRUN[1][2]) - { - switch(MMU.timerMODE[1][2]) - { - case 0xFFFF : - if(nds.timerOver[1][1]) - { - ++(MMU.timer[1][2]); - nds.timerOver[1][2] = !MMU.timer[1][2]; - if (nds.timerOver[1][2]) - { - if(T1ReadWord(MMU.ARM7_REG, 0x10A) & 0x40) - NDS_makeARM7Int(5); - MMU.timer[1][2] = MMU.timerReload[1][2]; - } - } - break; - default : - { - nds.diff = (nds.cycles - nds.timerCycle[1][2])>>MMU.timerMODE[1][2]; - nds.old = MMU.timer[1][2]; - MMU.timer[1][2] += nds.diff; - nds.timerCycle[1][2] += nds.diff << MMU.timerMODE[1][2]; - nds.timerOver[1][2] = nds.old>MMU.timer[1][2]; - if(nds.timerOver[1][2]) - { - if(T1ReadWord(MMU.ARM7_REG, 0x10A) & 0x40) - NDS_makeARM7Int(5); - MMU.timer[1][2] = MMU.timerReload[1][2]; - } - } - break; - } - } - else - { - MMU.timerRUN[1][2] = TRUE; - nds.timerCycle[1][2] = nds.cycles; - } - } - if(MMU.timerON[1][3]) - { - if(MMU.timerRUN[1][3]) - { - switch(MMU.timerMODE[1][3]) - { - case 0xFFFF : - if(nds.timerOver[1][2]) - { - ++(MMU.timer[1][3]); - nds.timerOver[1][3] = !MMU.timer[1][3]; - if (nds.timerOver[1][3]) - { - if(T1ReadWord(MMU.ARM7_REG, 0x10E) & 0x40) - NDS_makeARM7Int(6); - MMU.timer[1][3] += MMU.timerReload[1][3]; - } - } - break; - default : - { - nds.diff = (nds.cycles - nds.timerCycle[1][3])>>MMU.timerMODE[1][3]; - nds.old = MMU.timer[1][3]; - MMU.timer[1][3] += nds.diff; - nds.timerCycle[1][3] += nds.diff << MMU.timerMODE[1][3]; - nds.timerOver[1][3] = nds.old>MMU.timer[1][3]; - if(nds.timerOver[1][3]) - { - if(T1ReadWord(MMU.ARM7_REG, 0x10E) & 0x40) - NDS_makeARM7Int(6); - MMU.timer[1][3] += MMU.timerReload[1][3]; - } - } - break; - } - } - else - { - MMU.timerRUN[1][3] = TRUE; - nds.timerCycle[1][3] = nds.cycles; - } - } - } + //what we find here is dependent on the timing constants above + if(nds_timer>next && (nds_timer-next)>16) + printf("curious. please report: over by %d\n",(int)(nds_timer-next)); - if (MMU.CheckDMAs) - { - - if((MMU.DMAing[0][0])&&(MMU.DMACycle[0][0]<=nds.cycles)) - { - T1WriteLong(ARM9Mem.ARM9_REG, 0xB8 + (0xC*0), T1ReadLong(ARM9Mem.ARM9_REG, 0xB8 + (0xC*0)) & 0x7FFFFFFF); - if((MMU.DMACrt[0][0])&(1<<30)) NDS_makeARM9Int(8); - MMU.DMAing[0][0] = FALSE; - MMU.CheckDMAs &= ~(1<<(0+(0<<2))); - } - - if((MMU.DMAing[0][1])&&(MMU.DMACycle[0][1]<=nds.cycles)) - { - T1WriteLong(ARM9Mem.ARM9_REG, 0xB8 + (0xC*1), T1ReadLong(ARM9Mem.ARM9_REG, 0xB8 + (0xC*1)) & 0x7FFFFFFF); - if((MMU.DMACrt[0][1])&(1<<30)) NDS_makeARM9Int(9); - MMU.DMAing[0][1] = FALSE; - MMU.CheckDMAs &= ~(1<<(1+(0<<2))); - } - - if((MMU.DMAing[0][2])&&(MMU.DMACycle[0][2]<=nds.cycles)) - { - T1WriteLong(ARM9Mem.ARM9_REG, 0xB8 + (0xC*2), T1ReadLong(ARM9Mem.ARM9_REG, 0xB8 + (0xC*2)) & 0x7FFFFFFF); - if((MMU.DMACrt[0][2])&(1<<30)) NDS_makeARM9Int(10); - MMU.DMAing[0][2] = FALSE; - MMU.CheckDMAs &= ~(1<<(2+(0<<2))); - } - - if((MMU.DMAing[0][3])&&(MMU.DMACycle[0][3]<=nds.cycles)) - { - T1WriteLong(ARM9Mem.ARM9_REG, 0xB8 + (0xC*3), T1ReadLong(ARM9Mem.ARM9_REG, 0xB8 + (0xC*3)) & 0x7FFFFFFF); - if((MMU.DMACrt[0][3])&(1<<30)) NDS_makeARM9Int(11); - MMU.DMAing[0][3] = FALSE; - MMU.CheckDMAs &= ~(1<<(3+(0<<2))); - } - - if((MMU.DMAing[1][0])&&(MMU.DMACycle[1][0]<=nds.cycles)) - { - T1WriteLong(MMU.ARM7_REG, 0xB8 + (0xC*0), T1ReadLong(MMU.ARM7_REG, 0xB8 + (0xC*0)) & 0x7FFFFFFF); - if((MMU.DMACrt[1][0])&(1<<30)) NDS_makeARM7Int(8); - MMU.DMAing[1][0] = FALSE; - MMU.CheckDMAs &= ~(1<<(0+(1<<2))); - } - - if((MMU.DMAing[1][1])&&(MMU.DMACycle[1][1]<=nds.cycles)) - { - T1WriteLong(MMU.ARM7_REG, 0xB8 + (0xC*1), T1ReadLong(MMU.ARM7_REG, 0xB8 + (0xC*1)) & 0x7FFFFFFF); - if((MMU.DMACrt[1][1])&(1<<30)) NDS_makeARM7Int(9); - MMU.DMAing[1][1] = FALSE; - MMU.CheckDMAs &= ~(1<<(1+(1<<2))); - } - - if((MMU.DMAing[1][2])&&(MMU.DMACycle[1][2]<=nds.cycles)) - { - T1WriteLong(MMU.ARM7_REG, 0xB8 + (0xC*2), T1ReadLong(MMU.ARM7_REG, 0xB8 + (0xC*2)) & 0x7FFFFFFF); - if((MMU.DMACrt[1][2])&(1<<30)) NDS_makeARM7Int(10); - MMU.DMAing[1][2] = FALSE; - MMU.CheckDMAs &= ~(1<<(2+(1<<2))); - } - - if((MMU.DMAing[1][3])&&(MMU.DMACycle[1][3]<=nds.cycles)) - { - T1WriteLong(MMU.ARM7_REG, 0xB8 + (0xC*3), T1ReadLong(MMU.ARM7_REG, 0xB8 + (0xC*3)) & 0x7FFFFFFF); - if((MMU.DMACrt[1][3])&(1<<30)) NDS_makeARM7Int(11); - MMU.DMAing[1][3] = FALSE; - MMU.CheckDMAs &= ~(1<<(3+(1<<2))); - } - } - -#ifndef USE_GEOMETRY_FIFO_EMULATION - if(MMU.reg_IE[ARMCPU_ARM9]&(1<<21)) - NDS_makeARM9Int(21); // GX geometry -#endif - - if((MMU.reg_IF[0]&MMU.reg_IE[0]) && (MMU.reg_IME[0])) - { -#ifdef GDB_STUB - if ( armcpu_flagIrq( &NDS_ARM9)) -#else - if ( armcpu_irqException(&NDS_ARM9)) -#endif - { - nds.ARM9Cycle = nds.cycles; - } - } - - if((MMU.reg_IF[1]&MMU.reg_IE[1]) && (MMU.reg_IME[1])) - { -#ifdef GDB_STUB - if ( armcpu_flagIrq( &NDS_ARM7)) -#else - if ( armcpu_irqException(&NDS_ARM7)) -#endif - { - nds.ARM7Cycle = nds.cycles; - } - } - - } // if(!nds.sleeping) - else - { - gpu_UpdateRender(); - if((MMU.reg_IE[1] & MMU.reg_IF[1]) & (1<<22)) - { - nds.sleeping = FALSE; - } - break; + //if we were waiting for an irq, don't wait too long: + //let's re-analyze it after this hardware event + if(NDS_ARM9.waitIRQ) nds_arm9_timer = nds_timer; + if(NDS_ARM7.waitIRQ) nds_arm7_timer = nds_timer; } } + //end of frame emulation housekeeping if(LagFrameFlag) { lagframecounter++; @@ -2501,11 +2147,238 @@ void NDS_exec(s32 nb) lastLag = lagframecounter; lagframecounter = 0; } - currFrameCounter++; cheatsProcess(); } +void execHardware_interrupts() +{ + //THIS IS A HACK but it is necessary until we have gxfifo emulation + #ifndef USE_GEOMETRY_FIFO_EMULATION + if(MMU.reg_IE[ARMCPU_ARM9]&(1<<21)) + NDS_makeARM9Int(21); // GX geometry + #endif + + if((MMU.reg_IF[0]&MMU.reg_IE[0]) && (MMU.reg_IME[0])) + { +#ifdef GDB_STUB + if ( armcpu_flagIrq( &NDS_ARM9)) +#else + if ( armcpu_irqException(&NDS_ARM9)) +#endif + { + //nds.ARM9Cycle = nds.cycles; + } + } + + if((MMU.reg_IF[1]&MMU.reg_IE[1]) && (MMU.reg_IME[1])) + { +#ifdef GDB_STUB + if ( armcpu_flagIrq( &NDS_ARM7)) +#else + if ( armcpu_irqException(&NDS_ARM7)) +#endif + { + //nds.ARM7Cycle = nds.cycles; + } + } +} + +bool _HACK_DONT_STOPMOVIE = false; +void NDS_Reset() +{ + u32 src; + u32 dst; + FILE* inf = 0; + NDS_header * header = NDS_getROMHeader(); + + if (!header) return ; + + if(movieMode != MOVIEMODE_INACTIVE && !_HACK_DONT_STOPMOVIE) + movie_reset_command = true; + + if(movieMode == MOVIEMODE_INACTIVE) { + currFrameCounter = 0; + lagframecounter = 0; + LagFrameFlag = 0; + lastLag = 0; + TotalLagFrames = 0; + } + + MMU_clearMem(); + MMU_new.backupDevice.reset(); + + //ARM7 BIOS IRQ HANDLER + if(CommonSettings.UseExtBIOS == true) + inf = fopen(CommonSettings.ARM7BIOS,"rb"); + else + inf = NULL; + + if(inf) { + fread(MMU.ARM7_BIOS,1,16384,inf); + fclose(inf); + if(CommonSettings.SWIFromBIOS == true) NDS_ARM7.swi_tab = 0; + else NDS_ARM7.swi_tab = ARM7_swi_tab; + INFO("ARM7 BIOS is loaded.\n"); + } else { + NDS_ARM7.swi_tab = ARM7_swi_tab; + _MMU_write32(0x00, 0xE25EF002); + _MMU_write32(0x04, 0xEAFFFFFE); + _MMU_write32(0x18, 0xEA000000); + _MMU_write32(0x20, 0xE92D500F); + _MMU_write32(0x24, 0xE3A00301); + _MMU_write32(0x28, 0xE28FE000); + _MMU_write32(0x2C, 0xE510F004); + _MMU_write32(0x30, 0xE8BD500F); + _MMU_write32(0x34, 0xE25EF004); + } + + //ARM9 BIOS IRQ HANDLER + if(CommonSettings.UseExtBIOS == true) + inf = fopen(CommonSettings.ARM9BIOS,"rb"); + else + inf = NULL; + //memcpy(ARM9Mem.ARM9_BIOS + 0x20, gba_header_data_0x04, 156); + + if(inf) { + fread(ARM9Mem.ARM9_BIOS,1,4096,inf); + fclose(inf); + if(CommonSettings.SWIFromBIOS == true) NDS_ARM9.swi_tab = 0; + else NDS_ARM9.swi_tab = ARM9_swi_tab; + INFO("ARM9 BIOS is loaded.\n"); + } else { + NDS_ARM9.swi_tab = ARM9_swi_tab; + _MMU_write32(0xFFFF0018, 0xEA000000); + _MMU_write32(0xFFFF0020, 0xE92D500F); + _MMU_write32(0xFFFF0024, 0xEE190F11); + _MMU_write32(0xFFFF0028, 0xE1A00620); + _MMU_write32(0xFFFF002C, 0xE1A00600); + _MMU_write32(0xFFFF0030, 0xE2800C40); + _MMU_write32(0xFFFF0034, 0xE28FE000); + _MMU_write32(0xFFFF0038, 0xE510F004); + _MMU_write32(0xFFFF003C, 0xE8BD500F); + _MMU_write32(0xFFFF0040, 0xE25EF004); + } + + /* Is it really needed ??? */ + _MMU_write32(0x0000004, 0xE3A0010E); + _MMU_write32(0x0000008, 0xE3A01020); + // _MMU_write32(0x000000C, 0xE1B02110); + _MMU_write32(0x000000C, 0xE1B02040); + _MMU_write32(0x0000010, 0xE3B02020); + // _MMU_write32(0x0000010, 0xE2100202); + + if(CommonSettings.UseExtFirmware == true) + NDS_LoadFirmware(CommonSettings.Firmware); + + if((CommonSettings.UseExtBIOS == true) && (CommonSettings.UseExtFirmware == true) && (CommonSettings.BootFromFirmware == true) && (fw_success == TRUE)) + { + for(int i = 0; i < nds.FW_ARM9BootCodeSize; i += 4) + { + _MMU_write32((nds.FW_ARM9BootCodeAddr + i), T1ReadLong(nds.FW_ARM9BootCode, i)); + } + + for(int i = 0; i < nds.FW_ARM7BootCodeSize; i += 4) + { + _MMU_write32((nds.FW_ARM7BootCodeAddr + i), T1ReadLong(nds.FW_ARM7BootCode, i)); + } + + armcpu_init(&NDS_ARM9, nds.FW_ARM9BootCodeAddr); + armcpu_init(&NDS_ARM7, nds.FW_ARM7BootCodeAddr); + //armcpu_init(&NDS_ARM9, 0xFFFF0000); + //armcpu_init(&NDS_ARM7, 0x00000000); + } + else + { + src = header->ARM9src; + dst = header->ARM9cpy; + + for(int i = 0; i < (header->ARM9binSize>>2); ++i) + { + _MMU_write32(dst, T1ReadLong(MMU.CART_ROM, src)); + dst += 4; + src += 4; + } + + src = header->ARM7src; + dst = header->ARM7cpy; + + for(int i = 0; i < (header->ARM7binSize>>2); ++i) + { + _MMU_write32(dst, T1ReadLong(MMU.CART_ROM, src)); + dst += 4; + src += 4; + } + + armcpu_init(&NDS_ARM7, header->ARM7exe); + armcpu_init(&NDS_ARM9, header->ARM9exe); + } + + nds.wifiCycle = 0; + memset(nds.timerCycle, 0, sizeof(u64) * 2 * 4); + nds.VCount = 0; + nds.old = 0; + nds.touchX = nds.touchY = 0; + nds.isTouch = 0; + nds.debugConsole = CommonSettings.DebugConsole; + SetupMMU(nds.debugConsole); + + _MMU_write16(0x04000130, 0x3FF); + _MMU_write16(0x04000130, 0x3FF); + _MMU_write08(0x04000136, 0x43); + + LidClosed = FALSE; + countLid = 0; + + /* + * Setup a copy of the firmware user settings in memory. + * (this is what the DS firmware would do). + */ + { + u8 temp_buffer[NDS_FW_USER_SETTINGS_MEM_BYTE_COUNT]; + int fw_index; + + if ( copy_firmware_user_data( temp_buffer, MMU.fw.data)) { + for ( fw_index = 0; fw_index < NDS_FW_USER_SETTINGS_MEM_BYTE_COUNT; fw_index++) + _MMU_write08(0x027FFC80 + fw_index, temp_buffer[fw_index]); + } + } + + // Copy the whole header to Main RAM 0x27FFE00 on startup. + // Reference: http://nocash.emubase.de/gbatek.htm#dscartridgeheader + //zero 27-jun-09 : why did this copy 0x90 more? gbatek says its not stored in ram. + //for (i = 0; i < ((0x170+0x90)/4); i++) { + for (int i = 0; i < ((0x170)/4); i++) { + _MMU_write32(0x027FFE00+i*4, LE_TO_LOCAL_32(((u32*)MMU.CART_ROM)[i])); + } + + // Write the header checksum to memory (the firmware needs it to see the cart) + _MMU_write16(0x027FF808, T1ReadWord(MMU.CART_ROM, 0x15E)); + + MainScreen.offset = 0; + SubScreen.offset = 192; + + //_MMU_write32[ARMCPU_ARM9](0x02007FFC, 0xE92D4030); + + delete header; + + Screen_Reset(); + gfx3d_reset(); + gpu3D->NDS_3D_Reset(); + SPU_Reset(); + +#ifdef EXPERIMENTAL_WIFI + WIFI_Init(&wifiMac); + + WIFI_SoftAP_Shutdown(&wifiMac); + WIFI_SoftAP_Init(&wifiMac); +#endif + + memcpy(FW_Mac, (MMU.fw.data + 0x36), 6); + + initSchedule(); +} + static std::string MakeInputDisplayString(u16 pad, const std::string* Buttons, int count) { std::string s; for (int x = 0; x < count; x++) { diff --git a/desmume/src/NDSSystem.h b/desmume/src/NDSSystem.h index 0b2193eba..4493d6559 100644 --- a/desmume/src/NDSSystem.h +++ b/desmume/src/NDSSystem.h @@ -173,19 +173,19 @@ struct NDS_header extern void debug(); void emu_halt(); +extern u64 nds_timer; +void NDS_Reschedule(); +void NDS_RescheduleGXFIFO(); +void NDS_RescheduleDMA(); +void NDS_RescheduleTimers(); + typedef struct { - s32 ARM9Cycle; - s32 ARM7Cycle; s32 wifiCycle; s32 cycles; - s32 timerCycle[2][4]; - BOOL timerOver[2][4]; - s32 nextHBlank; + u64 timerCycle[2][4]; u32 VCount; u32 old; - s32 diff; - BOOL lignerendu; u16 touchX; u16 touchY; diff --git a/desmume/src/armcpu.cpp b/desmume/src/armcpu.cpp index 59b70f98a..f8cf8bb46 100644 --- a/desmume/src/armcpu.cpp +++ b/desmume/src/armcpu.cpp @@ -318,7 +318,7 @@ u32 armcpu_switchMode(armcpu_t *armcpu, u8 mode) case FIQ : { - u32 tmp; + u32 tmp; SWAP(armcpu->R[8], armcpu->R8_fiq, tmp); SWAP(armcpu->R[9], armcpu->R9_fiq, tmp); SWAP(armcpu->R[10], armcpu->R10_fiq, tmp); diff --git a/desmume/src/armcpu.h b/desmume/src/armcpu.h index ff45635ca..8770c12aa 100644 --- a/desmume/src/armcpu.h +++ b/desmume/src/armcpu.h @@ -234,6 +234,8 @@ static INLINE void setIF(int PROCNUM, u32 flag) if(ARMPROC.waitIRQ) ARMPROC.newIrqFlags |= flag; + extern void NDS_Reschedule(); + NDS_Reschedule(); } static INLINE void NDS_makeARM9Int(u32 num) diff --git a/desmume/src/common.cpp b/desmume/src/common.cpp index 0ad7bd784..615649db1 100644 --- a/desmume/src/common.cpp +++ b/desmume/src/common.cpp @@ -161,4 +161,4 @@ std::string GetRomNameWithoutExtension() if (x > 0) return RomName.substr(0,x); else return RomName; -} \ No newline at end of file +} diff --git a/desmume/src/gfx3d.cpp b/desmume/src/gfx3d.cpp index 864e27fd9..9c0225952 100644 --- a/desmume/src/gfx3d.cpp +++ b/desmume/src/gfx3d.cpp @@ -61,8 +61,10 @@ in this function: */ static void gfx3d_doFlush(); #ifdef USE_GEOMETRY_FIFO_EMULATION -#define GFX_DELAY(x) MMU.gfx3dCycles = nds.cycles + (2*x) -#define GFX_DELAY_M2(x) MMU.gfx3dCycles += (2*x) +inline void GFX_DELAY(int x) { + MMU.gfx3dCycles = nds_timer + (2*x); NDS_RescheduleGXFIFO(); } +inline void GFX_DELAY_M2(int x) { + MMU.gfx3dCycles += (2*x); NDS_RescheduleGXFIFO(); } #else #define GFX_DELAY(x) #define GFX_DELAY_M2(x) diff --git a/desmume/src/readwrite.cpp b/desmume/src/readwrite.cpp index 78dfcab43..dc8ae1e5e 100644 --- a/desmume/src/readwrite.cpp +++ b/desmume/src/readwrite.cpp @@ -85,6 +85,8 @@ int write32le(u32 b, std::ostream* os) return 4; } +void writebool(bool b, std::ostream* os) { write32le(b?1:0,os); } + int write64le(u64 b, std::ostream* os) { u8 s[8]; @@ -155,6 +157,14 @@ int read32le(u32 *Bufo, std::istream *is) return 1; } +int readbool(bool *b, std::istream* is) +{ + u32 temp; + int ret = read32le(&temp,is); + *b = (bool)temp; + return ret; +} + int readbuffer(std::vector &vec, std::istream* is) { u32 size; diff --git a/desmume/src/readwrite.h b/desmume/src/readwrite.h index 7b4713fe3..6ee2f6225 100644 --- a/desmume/src/readwrite.h +++ b/desmume/src/readwrite.h @@ -21,6 +21,8 @@ int read32le(u32 *Bufo, FILE *fp); int read16le(u16 *Bufo, std::istream *is); inline int read16le(s16 *Bufo, std::istream* is) { return read16le((u16*)Bufo,is); } int read8le(u8 *Bufo, std::istream *is); +int readbool(bool *b, std::istream* is); +void writebool(bool b, std::ostream* os); int readbuffer(std::vector &vec, std::istream* is); int writebuffer(std::vector& vec, std::ostream* os); diff --git a/desmume/src/saves.cpp b/desmume/src/saves.cpp index c2ca05d15..07d49f82c 100644 --- a/desmume/src/saves.cpp +++ b/desmume/src/saves.cpp @@ -52,7 +52,7 @@ int lastSaveState = 0; //Keeps track of last savestate used for quick save/load savestates_t savestates[NB_STATES]; -#define SAVESTATE_VERSION 11 +#define SAVESTATE_VERSION 12 static const char* magic = "DeSmuME SState\0"; //a savestate chunk loader can set this if it wants to permit a silent failure (for compatibility) @@ -161,17 +161,10 @@ SFORMAT SF_MEM[]={ }; SFORMAT SF_NDS[]={ - { "_9CY", 4, 1, &nds.ARM9Cycle}, - { "_7CY", 4, 1, &nds.ARM7Cycle}, - { "_CYC", 4, 1, &nds.cycles}, { "_WCY", 4, 1, &nds.wifiCycle}, - { "_TCY", 4, 8, nds.timerCycle}, - { "_TOV", 4, 8, nds.timerOver}, - { "_NHB", 4, 1, &nds.nextHBlank}, + { "_TCY", 8, 8, nds.timerCycle}, { "_VCT", 4, 1, &nds.VCount}, { "_OLD", 4, 1, &nds.old}, - { "_DIF", 4, 1, &nds.diff}, - { "_LIG", 4, 1, &nds.lignerendu}, { "_TPX", 2, 1, &nds.touchX}, { "_TPY", 2, 1, &nds.touchY}, { "_TPB", 4, 1, &nds.isTouch}, @@ -200,6 +193,8 @@ SFORMAT SF_MMU[]={ { "MIME", 4, 2, MMU.reg_IME}, { "MIE_", 4, 2, MMU.reg_IE}, { "MIF_", 4, 2, MMU.reg_IF}, + + { "MGXC", 8, 1, &MMU.gfx3dCycles}, { "M_SX", 1, 2, &MMU.SPI_CNT}, { "M_SC", 1, 2, &MMU.SPI_CMD}, @@ -207,7 +202,7 @@ SFORMAT SF_MMU[]={ { "MASC", 1, 2, &MMU.AUX_SPI_CMD}, { "MDST", 4, 8, MMU.DMAStartTime}, - { "MDCY", 4, 8, MMU.DMACycle}, + { "MDCY", 8, 8, MMU.DMACycle}, { "MDCR", 4, 8, MMU.DMACrt}, { "MDMA", 4, 8, MMU.DMAing}, { "MDSR", 4, 8, DMASrc}, @@ -217,12 +212,12 @@ SFORMAT SF_MMU[]={ { "MDV2", 8, 1, &MMU.divResult}, { "MDV3", 8, 1, &MMU.divMod}, { "MDV4", 4, 1, &MMU.divCnt}, - { "MDV5", 4, 1, &MMU.divCycles}, + { "MDV5", 8, 1, &MMU.divCycles}, { "MSQ1", 4, 1, &MMU.sqrtRunning}, { "MSQ2", 4, 1, &MMU.sqrtResult}, { "MSQ3", 4, 1, &MMU.sqrtCnt}, - { "MSQ4", 4, 1, &MMU.sqrtCycles}, + { "MSQ4", 8, 1, &MMU.sqrtCycles}, //begin memory chips //we are skipping the firmware, because we really don't want to save the firmware to the savestate @@ -262,6 +257,9 @@ SFORMAT SF_MOVIE[]={ { 0 } }; +void nds_savestate(std::ostream* os); +bool nds_loadstate(std::istream* is, int size); + static void mmu_savestate(std::ostream* os) { //version @@ -824,6 +822,7 @@ static void writechunks(std::ostream* os) { savestate_WriteChunk(os,3,cp15_savestate); savestate_WriteChunk(os,4,SF_MEM); savestate_WriteChunk(os,5,SF_NDS); + savestate_WriteChunk(os,51,nds_savestate); savestate_WriteChunk(os,60,SF_MMU); savestate_WriteChunk(os,61,mmu_savestate); savestate_WriteChunk(os,7,gpu_savestate); @@ -852,6 +851,7 @@ static bool ReadStateChunks(std::istream* is, s32 totalsize) case 3: if(!cp15_loadstate(is,size)) ret=false; break; case 4: if(!ReadStateChunk(is,SF_MEM,size)) ret=false; break; case 5: if(!ReadStateChunk(is,SF_NDS,size)) ret=false; break; + case 51: if(!nds_loadstate(is,size)) ret=false; break; case 60: if(!ReadStateChunk(is,SF_MMU,size)) ret=false; break; case 61: if(!mmu_loadstate(is,size)) ret=false; break; case 7: if(!gpu_loadstate(is,size)) ret=false; break; diff --git a/desmume/src/types.h b/desmume/src/types.h index 15fc6a620..5fe445bca 100644 --- a/desmume/src/types.h +++ b/desmume/src/types.h @@ -105,7 +105,7 @@ typedef unsigned char u8; typedef unsigned short u16; typedef unsigned int u32; -typedef unsigned long u64; +typedef unsigned long long u64; typedef signed char s8; typedef signed short s16; diff --git a/desmume/src/windows/DeSmuME_2005.vcproj b/desmume/src/windows/DeSmuME_2005.vcproj index e677c4a36..01235a6d2 100644 --- a/desmume/src/windows/DeSmuME_2005.vcproj +++ b/desmume/src/windows/DeSmuME_2005.vcproj @@ -594,6 +594,22 @@ > + + + + + + + + - - @@ -958,10 +970,6 @@ RelativePath="..\GPU_osd.h" > - - @@ -1090,10 +1098,6 @@ RelativePath="..\saves.h" > - - diff --git a/desmume/src/windows/main.cpp b/desmume/src/windows/main.cpp index 1ebebe6b5..1746400b7 100644 --- a/desmume/src/windows/main.cpp +++ b/desmume/src/windows/main.cpp @@ -924,8 +924,8 @@ DWORD WINAPI run() for(int i=0;i<16;i++) load = load/8 + nds.runCycleCollector[(i+nds.idleFrameCounter)&15]*7/8; load = std::min(100,std::max(0,(int)(load*100/1120380))); - sprintf(txt,"(%02d%%) %s", load, DESMUME_NAME_AND_VERSION); - SetWindowText(hwnd, txt); + //sprintf(txt,"(%02d%%) %s", load, DESMUME_NAME_AND_VERSION); + SetWindowText(hwnd, DESMUME_NAME_AND_VERSION); } if(!skipnextframe)