diff --git a/desmume/src/FIFO.cpp b/desmume/src/FIFO.cpp index fbfb304bd..3807b6382 100644 --- a/desmume/src/FIFO.cpp +++ b/desmume/src/FIFO.cpp @@ -144,6 +144,10 @@ void IPC_FIFOcnt(u8 proc, u16 val) GFX_PIPE gxPIPE; GFX_FIFO gxFIFO; + + + + void GFX_PIPEclear() { gxPIPE.head = 0; @@ -153,192 +157,122 @@ void GFX_PIPEclear() void GFX_FIFOclear() { - u32 gxstat = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x600); - gxstat &= 0x0000FFFF; - gxFIFO.head = 0; gxFIFO.tail = 0; gxFIFO.size = 0; - gxstat |= 0x06000000; - T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x600, gxstat); +} + +static void GXF_FIFO_handleEvents() +{ + if(gxFIFO.size <= 127) + { + //TODO - should this always happen, over and over, until the dma is disabled? + //or only when we change to this state? + if(MMU_new.gxstat.gxfifo_irq == 1) + setIF(0, (1<<21)); //the half gxfifo irq + + //might need to trigger a gxfifo dma + triggerDma(EDMAMode_GXFifo); + } + + + + if(gxFIFO.size == 0) { + //we just went to empty + if(MMU_new.gxstat.gxfifo_irq == 2) + setIF(0, (1<<21)); //the empty gxfifo irq + } + } void GFX_FIFOsend(u8 cmd, u32 param) { - u32 gxstat = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x600); + if(cmd==0x41) { + int zzz=9; + } //INFO("gxFIFO: send 0x%02X = 0x%08X (size %03i/0x%02X) gxstat 0x%08X\n", cmd, param, gxFIFO.size, gxFIFO.size, gxstat); + //printf("fifo recv: %02X: %08X upto:%d\n",cmd,param,gxFIFO.size+1); - gxstat &= 0xF000FFFF; + //TODO - WOAH ! NOT HANDLING A TOO-BIG FIFO RIGHT NOW! + //if (gxFIFO.size > 255) + //{ + // GXF_FIFO_handleEvents(); + // //NEED TO HANDLE THIS!!!!!!!!!!!!!!!!!!!!!!!!!! - if (gxFIFO.size == 0) // FIFO empty - { - gxstat |= 0x06000000; - if (gxPIPE.size < 4) // pipe not full - { - gxPIPE.cmd[gxPIPE.tail] = cmd; - gxPIPE.param[gxPIPE.tail] = param; - gxPIPE.tail++; - gxPIPE.size++; - if (gxPIPE.tail > 3) gxPIPE.tail = 0; - -#ifdef USE_GEOMETRY_FIFO_EMULATION - gxstat |= 0x08000000; // set busy flag -#endif - T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x600, gxstat); - NDS_RescheduleGXFIFO(); - return; - } - } + // //gxstat |= 0x08000000; // busy + // NDS_RescheduleGXFIFO(1); + // //INFO("ERROR: gxFIFO is full (cmd 0x%02X = 0x%08X) (prev cmd 0x%02X = 0x%08X)\n", cmd, param, gxFIFO.cmd[255], gxFIFO.param[255]); + // return; + //} - if (gxFIFO.size > 255) - { -#ifdef USE_GEOMETRY_FIFO_EMULATION - gxstat |= 0x01000000; // full - gxstat |= 0x08000000; // busy -#else - gxstat |= 0x02000000; // this is hack (must be removed later) -#endif - T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x600, gxstat); - NDS_RescheduleGXFIFO(); - //INFO("ERROR: gxFIFO is full (cmd 0x%02X = 0x%08X) (prev cmd 0x%02X = 0x%08X)\n", cmd, param, gxFIFO.cmd[255], gxFIFO.param[255]); - return; - } gxFIFO.cmd[gxFIFO.tail] = cmd; gxFIFO.param[gxFIFO.tail] = param; gxFIFO.tail++; gxFIFO.size++; - if (gxFIFO.tail > 255) gxFIFO.tail = 0; - -#ifdef USE_GEOMETRY_FIFO_EMULATION - gxstat |= 0x08000000; // set busy flag -#endif + if (gxFIFO.tail > HACK_GXIFO_SIZE-1) gxFIFO.tail = 0; - gxstat |= ((gxFIFO.size & 0x1FF) << 16); - - if (gxFIFO.size < 128) // less half - { - gxstat |= 0x02000000; + if(gxFIFO.size>=HACK_GXIFO_SIZE) { + printf("--FIFO FULL-- : %d\n",gxFIFO.size); } - -#ifndef USE_GEOMETRY_FIFO_EMULATION - gxstat |= 0x02000000; // this is hack (must be removed later) -#endif - - T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x600, gxstat); - NDS_RescheduleGXFIFO(); + //gxstat |= 0x08000000; // set busy flag + + GXF_FIFO_handleEvents(); + + NDS_RescheduleGXFIFO(1); } // this function used ONLY in gxFIFO BOOL GFX_PIPErecv(u8 *cmd, u32 *param) { - u32 gxstat = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x600); - gxstat &= 0xF7FFFFFF; // clear busy flag + //gxstat &= 0xF7FFFFFF; // clear busy flag - if (gxPIPE.size > 0) + if (gxFIFO.size == 0) { - *cmd = gxPIPE.cmd[gxPIPE.head]; - *param = gxPIPE.param[gxPIPE.head]; - gxPIPE.head++; - gxPIPE.size--; - if (gxPIPE.head > 3) gxPIPE.head = 0; - - if (gxPIPE.size < 3) - { - if (gxFIFO.size > 0) - { - gxstat &= 0xF000FFFF; - - gxPIPE.cmd[gxPIPE.tail] = gxFIFO.cmd[gxFIFO.head]; - gxPIPE.param[gxPIPE.tail] = gxFIFO.param[gxFIFO.head]; - gxPIPE.tail++; - gxPIPE.size++; - if (gxPIPE.tail > 3) gxPIPE.tail = 0; - - gxFIFO.head++; - gxFIFO.size--; - if (gxFIFO.head > 255) gxFIFO.head = 0; - - if (gxFIFO.size > 0) - { - gxPIPE.cmd[gxPIPE.tail] = gxFIFO.cmd[gxFIFO.head]; - gxPIPE.param[gxPIPE.tail] = gxFIFO.param[gxFIFO.head]; - gxPIPE.tail++; - gxPIPE.size++; - if (gxPIPE.tail > 3) gxPIPE.tail = 0; - - gxFIFO.head++; - gxFIFO.size--; - if (gxFIFO.head > 255) gxFIFO.head = 0; - } - - gxstat |= ((gxFIFO.size & 0x1FF) << 16); - - if (gxFIFO.size < 128) - { - gxstat |= 0x02000000; - if (gxstat & 0x40000000) // IRQ: less half - { - setIF(0, (1<<21)); - } - execHardware_doAllDma(EDMAMode_GXFifo); - } - - if (gxFIFO.size == 0) // empty - { - gxstat |= 0x04000000; - if (gxstat & 0x80000000) // IRQ: empty - setIF(0, (1<<21)); - } - } - else // FIFO empty - { - gxstat &= 0xF000FFFF; - gxstat |= 0x06000000; - if (gxstat & 0x80000000) // IRQ: empty - setIF(0, (1<<21)); - } - } - - if (gxPIPE.size > 0) - gxstat |= 0x08000000; // set busy flag - T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x600, gxstat); - return (TRUE); + GXF_FIFO_handleEvents(); + return FALSE; } - if (gxstat & 0x80000000) // IRQ: empty - setIF(0, (1<<21)); - T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x600, gxstat); - return FALSE; + *cmd = gxFIFO.cmd[gxFIFO.head]; + *param = gxFIFO.param[gxFIFO.head]; + + gxFIFO.head++; + gxFIFO.size--; + if (gxFIFO.head > HACK_GXIFO_SIZE-1) gxFIFO.head = 0; + + GXF_FIFO_handleEvents(); + + return (TRUE); } void GFX_FIFOcnt(u32 val) { - u32 gxstat = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x600); - //INFO("gxFIFO: write cnt 0x%08X (prev 0x%08X) FIFO size %03i PIPE size %03i\n", val, gxstat, gxFIFO.size, gxPIPE.size); + //zeromus: i dont like any of this. - if (val & (1<<29)) // clear? (only in homebrew?) - { - GFX_PIPEclear(); - GFX_FIFOclear(); - return; - } + ////INFO("gxFIFO: write cnt 0x%08X (prev 0x%08X) FIFO size %03i PIPE size %03i\n", val, gxstat, gxFIFO.size, gxPIPE.size); - if (val & (1<<15)) // projection stack pointer reset - { - gfx3d_ClearStack(); - val &= 0xFFFF5FFF; // clear reset (bit15) & stack level (bit13) - } + //if (val & (1<<29)) // clear? (only in homebrew?) + //{ + // GFX_PIPEclear(); + // GFX_FIFOclear(); + // return; + //} - T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x600, val); + //if (val & (1<<15)) // projection stack pointer reset + //{ + // gfx3d_ClearStack(); + // val &= 0xFFFF5FFF; // clear reset (bit15) & stack level (bit13) + //} - if (gxFIFO.size == 0) // empty - { - if (val & 0x80000000) // IRQ: empty - setIF(0, (1<<21)); - } + //T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x600, val); + + //if (gxFIFO.size == 0) // empty + //{ + // if (val & 0x80000000) // IRQ: empty + // setIF(0, (1<<21)); + //} } // ========================================================= DISP FIFO diff --git a/desmume/src/FIFO.h b/desmume/src/FIFO.h index 1fe1b4ff4..40c1057d3 100644 --- a/desmume/src/FIFO.h +++ b/desmume/src/FIFO.h @@ -26,8 +26,6 @@ #ifndef FIFO_H #define FIFO_H -//#define USE_GEOMETRY_FIFO_EMULATION //enable gxFIFO emulation - #include "types.h" //=================================================== IPC FIFO @@ -47,14 +45,20 @@ extern u32 IPC_FIFOrecv(u8 proc); extern void IPC_FIFOcnt(u8 proc, u16 val); //=================================================== GFX FIFO + +//yeah, its oversize for now. thats a simpler solution +//moon seems to overdrive the fifo with immediate dmas +//i think this might be nintendo code too +#define HACK_GXIFO_SIZE 200000 + typedef struct { - u8 cmd[256]; - u32 param[256]; + u8 cmd[HACK_GXIFO_SIZE]; + u32 param[HACK_GXIFO_SIZE]; - u16 head; // start position - u16 tail; // tail - u16 size; // size FIFO buffer + u32 head; // start position + u32 tail; // tail + u32 size; // size FIFO buffer } GFX_FIFO; typedef struct diff --git a/desmume/src/MMU.cpp b/desmume/src/MMU.cpp index 5bb553220..d3da537a6 100644 --- a/desmume/src/MMU.cpp +++ b/desmume/src/MMU.cpp @@ -44,8 +44,13 @@ #include "addons.h" #include "mic.h" #include "movie.h" +#include "readwrite.h" #include "MMU_timing.h" +#ifdef WIN32 +#include "windows/IORegView.h" +#endif + #ifdef DO_ASSERT_UNALIGNED #define ASSERT_UNALIGNED(x) assert(x) #else @@ -969,6 +974,8 @@ void MMU_Reset() MMU.dscard[ARMCPU_ARM7].transfer_count = 0; MMU.dscard[ARMCPU_ARM7].mode = CardMode_Normal; + new(&MMU_new) MMU_struct_new; + MMU_timing.arm7codeFetch.Reset(); MMU_timing.arm7dataFetch.Reset(); MMU_timing.arm9codeFetch.Reset(); @@ -1267,12 +1274,12 @@ void FASTCALL MMU_writeToGCControl(u32 val) T1WriteLong(MMU.MMU_MEM[PROCNUM][0x40], 0x1A4, val); // Launch DMA if start flag was set to "DS Cart" - if(MMU.DMAStartTime[PROCNUM][0] == EDMAMode_Card) MMU_doDMA(0); - if(MMU.DMAStartTime[PROCNUM][1] == EDMAMode_Card) MMU_doDMA(1); - if(MMU.DMAStartTime[PROCNUM][2] == EDMAMode_Card) MMU_doDMA(2); - if(MMU.DMAStartTime[PROCNUM][3] == EDMAMode_Card) MMU_doDMA(3); + //printf("triggering card dma\n"); + triggerDma(EDMAMode_Card); } + + template u32 MMU_readFromGC() { @@ -1408,147 +1415,152 @@ u32 MMU_readFromGC() return val; } -template -void FASTCALL MMU_doDMA(u32 num) -{ -#ifdef USE_GEOMETRY_FIFO_EMULATION - if (MMU.DMAStartTime[PROCNUM][num] == EDMAMode_GXFifo) - if (MMU.DMACompleted[PROCNUM][num]) return; -#endif - u32 src = DMASrc[PROCNUM][num]; - u32 dst = DMADst[PROCNUM][num]; - u32 taille = 0; - bool paused = false; - - //if (dst == 0x022DD4E0) - // printf("proc %i dma %i: src=%08X, dst=%08X, size=%i, repmode=%i\n", - // PROCNUM, num, src, dst, (MMU.DMACrt[PROCNUM][num]&0x1FFFFF), MMU.DMAStartTime[PROCNUM][num]); - -#ifdef USE_GEOMETRY_FIFO_EMULATION - if (MMU.DMAStartTime[PROCNUM][num]== EDMAMode_GXFifo) - { - if (gxFIFO.size > 127) return; - } -#endif - - if(src==dst) - { - T1WriteLong(MMU.MMU_MEM[PROCNUM][0x40], 0xB8 + (0xC*num), T1ReadLong(MMU.MMU_MEM[PROCNUM][0x40], 0xB8 + (0xC*num)) & 0x7FFFFFFF); - return; - } - - if((!(MMU.DMACrt[PROCNUM][num]&(1<<31)))&&(!(MMU.DMACrt[PROCNUM][num]&(1<<25)))) - { /* not enabled and not to be repeated */ - MMU.DMAStartTime[PROCNUM][num] = 0; - MMU.DMACycle[PROCNUM][num] = 0; - //MMU.DMAing[PROCNUM][num] = FALSE; - return; - } - - //word count - taille = (MMU.DMACrt[PROCNUM][num]&0x1FFFFF); - if(taille == 0) taille = 0x200000; //according to gbatek.. - - //for main memory display fifo dmas, check for normal conditions and then dma all 128 bytes at once - //(theyll get sent to the fifo, which can handle more than it ought to be able to) - if ((MMU.DMAStartTime[PROCNUM][num]==EDMAMode_MemDisplay) && - (taille==4) && - (((MMU.DMACrt[PROCNUM][num]>>26)&1) == 1)) - taille = 128; - - if(MMU.DMAStartTime[PROCNUM][num] == EDMAMode_Card) - taille *= 0x80; - - 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))); - - DMALOG("ARM%c: DMA%d run src=%08X dst=%08X start=%d taille=%d repeat=%s %08X\r\n", - (PROCNUM==0)?'9':'7', num, src, dst, MMU.DMAStartTime[PROCNUM][num], taille, - (MMU.DMACrt[PROCNUM][num]&(1<<25))?"on":"off",MMU.DMACrt[PROCNUM][num]); - -#ifndef USE_GEOMETRY_FIFO_EMULATION - if(!(MMU.DMACrt[PROCNUM][num]&(1<<25))) - MMU.DMAStartTime[PROCNUM][num] = 0; -#endif - - NDS_RescheduleDMA(); - - // transfer - { - u32 i=0; - // 32 bit or 16 bit transfer ? - int sz = ((MMU.DMACrt[PROCNUM][num]>>26)&1)? 4 : 2; - int dstinc,srcinc; - int u=(MMU.DMACrt[PROCNUM][num]>>21); - switch(u & 0x3) { - case 0 : dstinc = sz; break; - case 1 : dstinc = -sz; break; - case 2 : dstinc = 0; break; - case 3 : dstinc = sz; break; //reload - default: - return; - } - switch((u >> 2)&0x3) { - case 0 : srcinc = sz; break; - case 1 : srcinc = -sz; break; - case 2 : srcinc = 0; break; - case 3 : // reserved - return; - default: - return; - } - - //if these do not use MMU_AT_DMA and the corresponding code in the read/write routines, - //then danny phantom title screen will be filled with a garbage char which is made by - //dmaing from 0x00000000 to 0x06000000 - if ((MMU.DMACrt[PROCNUM][num]>>26)&1) - for(; i < taille; ++i) - { -#ifdef USE_GEOMETRY_FIFO_EMULATION - if (MMU.DMAStartTime[PROCNUM][num] == EDMAMode_GXFifo) - { - if ( gxFIFO.size > 255 ) - { - if (i >= taille) break; - - paused = true; - MMU.DMACrt[PROCNUM][num] &= 0xFFE00000; - MMU.DMACrt[PROCNUM][num] |= ((taille-i) & 0x1FFFFF); - MMU.DMAing[PROCNUM][num] = FALSE; - MMU.DMACycle[PROCNUM][num] = nds_timer+1; - break; - } - } -#endif - _MMU_write32(dst, _MMU_read32(src)); - dst += dstinc; - src += srcinc; - } - else - for(; i < taille; ++i) - { - _MMU_write16(dst, _MMU_read16(src)); - dst += dstinc; - src += srcinc; - } - - //write back the addresses - DMASrc[PROCNUM][num] = src; - if((u & 0x3)!=3) //but dont write back dst if we were supposed to reload - DMADst[PROCNUM][num] = dst; - - //this is probably not the best place to do it, but the dma code in ndssystem is so bad i didnt want to touch it - //until it all gets rewritten. so this is here as a reminder, at least. - //(there is no proof for this code, but it is reasonable) - T1WriteLong(MMU.MMU_MEM[PROCNUM][0x40], 0xB0+12*num, DMASrc[PROCNUM][num]); - T1WriteLong(MMU.MMU_MEM[PROCNUM][0x40], 0xB4+12*num, DMADst[PROCNUM][num]); - - if (!paused) - MMU.DMACompleted[PROCNUM][num] = true; - } -} +//template +//void FASTCALL MMU_doDMA(u32 num) +//{ +// u32 src = DMASrc[PROCNUM][num]; +// u32 dst = DMADst[PROCNUM][num]; +// u32 taille = 0; +// bool paused = false; +// +// //if (dst == 0x022DD4E0) +// // printf("proc %i dma %i: src=%08X, dst=%08X, size=%i, repmode=%i\n", +// // PROCNUM, num, src, dst, (MMU.DMACrt[PROCNUM][num]&0x1FFFFF), MMU.DMAStartTime[PROCNUM][num]); +// +// +// if(src==dst) +// { +// T1WriteLong(MMU.MMU_MEM[PROCNUM][0x40], 0xB8 + (0xC*num), T1ReadLong(MMU.MMU_MEM[PROCNUM][0x40], 0xB8 + (0xC*num)) & 0x7FFFFFFF); +// return; +// } +// +// +// if((!(MMU.DMACrt[PROCNUM][num]&(1<<31)))&&(!(MMU.DMACrt[PROCNUM][num]&(1<<25)))) +// { /* not enabled and not to be repeated */ +// MMU.DMAStartTime[PROCNUM][num] = 0; +// MMU.DMACycle[PROCNUM][num] = 0; +// //MMU.DMAing[PROCNUM][num] = FALSE; +// return; +// } +// +// //word count +// taille = (MMU.DMACrt[PROCNUM][num]&0x1FFFFF); +// if(taille == 0) taille = 0x200000; //according to gbatek.. +// +// //for main memory display fifo dmas, check for normal conditions and then dma all 128 bytes at once +// //(theyll get sent to the fifo, which can handle more than it ought to be able to) +// if ((MMU.DMAStartTime[PROCNUM][num]==EDMAMode_MemDisplay) && +// (taille==4) && +// (((MMU.DMACrt[PROCNUM][num]>>26)&1) == 1)) +// taille = 128; +// +// if(MMU.DMAStartTime[PROCNUM][num] == EDMAMode_Card) +// taille *= 0x80; +// +// if(MMU.DMAStartTime[PROCNUM][num] == EDMAMode_GXFifo) { +// u32 todo = std::min(taille,(u32)112); +// //not necessarily the best time to do this... +// //we send 112 words at a time to gxfifo. +// //we need to deduct whatever we send from the counter in the dma controller +// u32 remain = taille - todo; +// taille = todo; +// MMU.DMACrt[PROCNUM][num] &= ~0x1FFFFF; +// MMU.DMACrt[PROCNUM][num] |= remain; +// if(remain != 0) paused = true; +// +// //not a good time to do this either but i have no choice right now.. +// if(remain == 0) { +// //disable the channel +// u8* regs = PROCNUM==0?MMU.ARM9_REG:MMU.ARM7_REG; +// T1WriteLong(regs, 0xB8 + (0xC*num), T1ReadLong(regs, 0xB8 + (0xC*num)) & 0x7FFFFFFF); +// MMU.DMACrt[PROCNUM][num] &= 0x7FFFFFFF; //blehhh i hate this shit being mirrored in memory +// } +// } +// +// 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))); +// +// DMALOG("ARM%c: DMA%d run src=%08X dst=%08X start=%d taille=%d repeat=%s %08X\r\n", +// (PROCNUM==0)?'9':'7', num, src, dst, MMU.DMAStartTime[PROCNUM][num], taille, +// (MMU.DMACrt[PROCNUM][num]&(1<<25))?"on":"off",MMU.DMACrt[PROCNUM][num]); +// +// NDS_RescheduleDMA(); +// +// // transfer +// { +// u32 i=0; +// // 32 bit or 16 bit transfer ? +// int sz = ((MMU.DMACrt[PROCNUM][num]>>26)&1)? 4 : 2; +// int dstinc,srcinc; +// int u=(MMU.DMACrt[PROCNUM][num]>>21); +// switch(u & 0x3) { +// case 0 : dstinc = sz; break; +// case 1 : dstinc = -sz; break; +// case 2 : dstinc = 0; break; +// case 3 : dstinc = sz; break; //reload +// default: +// return; +// } +// switch((u >> 2)&0x3) { +// case 0 : srcinc = sz; break; +// case 1 : srcinc = -sz; break; +// case 2 : srcinc = 0; break; +// case 3 : // reserved +// return; +// default: +// return; +// } +// +// //if these do not use MMU_AT_DMA and the corresponding code in the read/write routines, +// //then danny phantom title screen will be filled with a garbage char which is made by +// //dmaing from 0x00000000 to 0x06000000 +// if ((MMU.DMACrt[PROCNUM][num]>>26)&1) +// for(; i < taille; ++i) +// { +// if (MMU.DMAStartTime[PROCNUM][num] == EDMAMode_GXFifo) +// { +// /*if ( gxFIFO.size > 255 ) +// { +// paused = true; +// MMU.DMACrt[PROCNUM][num] &= 0xFFE00000; +// MMU.DMACrt[PROCNUM][num] |= ((taille-i) & 0x1FFFFF); +// MMU.DMAing[PROCNUM][num] = FALSE; +// MMU.DMACycle[PROCNUM][num] = nds_timer+1; +// break; +// }*/ +// +// printf("DMAING TO GXFIFO FROM: %08X, val:%08X (fifosize:%d)\n",src,_MMU_read32(src),gxFIFO.size); +// } +// +// _MMU_write32(dst, _MMU_read32(src)); +// dst += dstinc; +// src += srcinc; +// } +// else +// for(; i < taille; ++i) +// { +// _MMU_write16(dst, _MMU_read16(src)); +// dst += dstinc; +// src += srcinc; +// } +// +// //write back the addresses +// DMASrc[PROCNUM][num] = src; +// if((u & 0x3)!=3) //but dont write back dst if we were supposed to reload +// DMADst[PROCNUM][num] = dst; +// +// //this is probably not the best place to do it, but the dma code in ndssystem is so bad i didnt want to touch it +// //until it all gets rewritten. so this is here as a reminder, at least. +// //(there is no proof for this code, but it is reasonable) +// T1WriteLong(MMU.MMU_MEM[PROCNUM][0x40], 0xB0+12*num, DMASrc[PROCNUM][num]); +// T1WriteLong(MMU.MMU_MEM[PROCNUM][0x40], 0xB4+12*num, DMADst[PROCNUM][num]); +// +// if (!paused) +// MMU.DMACompleted[PROCNUM][num] = true; +// } +//} #ifdef MMU_ENABLE_ACL @@ -1617,6 +1629,21 @@ void FASTCALL MMU_write32_acl(u32 proc, u32 adr, u32 val) #define PROFILE_PREFETCH 1 #define profile_memory_access(X,Y,Z) +//does some validation on the game's choice of IF value, correcting it if necessary +void validateIF_arm9() +{ + //according to gbatek, these flags are forced on until the condition is removed. + //no proof of this though... + if(MMU_new.gxstat.gxfifo_irq == 1) + if(gxFIFO.size <= 127) + MMU.reg_IF[ARMCPU_ARM9] |= (1<<21); + else MMU.reg_IF[ARMCPU_ARM9] &= ~(1<<21); + else if(MMU_new.gxstat.gxfifo_irq == 2) + if(gxFIFO.size == 0) + MMU.reg_IF[ARMCPU_ARM9] |= (1<<21); + else MMU.reg_IF[ARMCPU_ARM9] &= ~(1<<21); + else if(MMU_new.gxstat.gxfifo_irq == 0) MMU.reg_IF[ARMCPU_ARM9] &= ~(1<<21); +} static INLINE void MMU_IPCSync(u8 proc, u32 val) { @@ -1712,56 +1739,481 @@ static INLINE void write_timer(int proc, int timerIndex, u16 val) NDS_RescheduleTimers(); } -template static INLINE void write_dma_hictrl(const int dmanum, const u16 val) +//template 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; +// MMU.DMACompleted[proc][dmanum] = false; +// MMU.DMAing[proc][dmanum] = false; +// +// if(MMU.DMAStartTime[proc][dmanum] == EDMAMode_Immediate) +// { +// MMU_doDMA(dmanum); +// } +// +// if (MMU.DMAStartTime[proc][dmanum] == EDMAMode_GXFifo) +// { +////#ifdef _3DINFO +//// INFO("ARM%c: DMA%d control src=0x%08X dst=0x%08X %s (gxFIFO tail %03i)\n", (proc==0)?'9':'7', dmanum, DMASrc[proc][dmanum], DMADst[proc][dmanum], ((val>>15)&0x01)?"ON":"OFF", gxFIFO.tail); +////#endif +// //if the gxfifo is ready to receive a dma, we need to trigger it now +// if(gxFIFO.size <= 127) +// MMU_doDMA(dmanum); +// } +// +// +// DMALOG("ARM%c: DMA%d control src=0x%08X dst=0x%08X %s\n", (proc==0)?'9':'7', dmanum, DMASrc[proc][dmanum], DMADst[proc][dmanum], ((val>>15)&0x01)?"ON":"OFF"); +// +// NDS_RescheduleDMA(); +//} + +u32 TGXSTAT::read32() { - u32 baseAddr = 0xB0 + dmanum*12; + u32 ret = 0; - //write this control value - T1WriteWord(MMU.MMU_MEM[proc][0x40], baseAddr+10, val); + tr = 1; //HACK!!!! tests no work now! (need this to make ff4 entities show up) + tb = 0; //HACK!!!! tests no work now! (need this to make ff4 entities show up) - //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); + ret |= tb|(tr<<1); - //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; - MMU.DMACompleted[proc][dmanum] = false; - MMU.DMAing[proc][dmanum] = false; + int _hack_getMatrixStackLevel(int which); + + ret |= ((_hack_getMatrixStackLevel(0) << 13) | (_hack_getMatrixStackLevel(1) << 8)); //matrix stack levels //no proof that these are needed yet -#ifdef USE_GEOMETRY_FIFO_EMULATION - if(MMU.DMAStartTime[proc][dmanum] == EDMAMode_Immediate) - { - MMU_doDMA(dmanum); + //todo: stack busy flag (bit14) + + ret |= se<<15; + ret |= (std::min(gxFIFO.size,(u32)255))<<16; + if(gxFIFO.size>=255) ret |= BIT(24); //fifo full + if(gxFIFO.size<128) ret |= BIT(25); //fifo half + if(gxFIFO.size==0) ret |= BIT(26); //fifo empty + //determine busy flag. + //if we're waiting for a flush, we're busy + if(isSwapBuffers) ret |= BIT(27); + //if fifo is nonempty, we're busy + if(gxFIFO.size!=0) ret |= BIT(27); + + + + + ret |= gxfifo_irq; //user's irq flags + + //printf("Returning gxstat read: %08X\n",ret); + return ret; +} + +void TGXSTAT::write32(const u32 val) +{ + gxfifo_irq = (val>>30)&3; + if(BIT15(val)) se = 0; //clear stack error flag + //if(BIT15(val)) gfx3d_ClearStack(); //?? + //printf("gxstat write: %08X while gxfifo.size=%d\n",val,gxFIFO.size); + + //if (val & (1<<29)) // clear? (only in homebrew?) + //{ + // GFX_PIPEclear(); + // GFX_FIFOclear(); + // return; + //} +} + +void TGXSTAT::savestate(EMUFILE *f) +{ + write32le(0,f); //version + write8le(tb,f); write8le(tr,f); write8le(se,f); write8le(gxfifo_irq,f); +} +bool TGXSTAT::loadstate(EMUFILE *f) +{ + u32 version; + if(read32le(&version,f) != 1) return false; + if(version != 0) return false; + + read8le(&tb,f); read8le(&tr,f); read8le(&se,f); read8le(&gxfifo_irq,f); + + return true; +} + +//this could be inlined... +void MMU_struct_new::write_dma(const int proc, const int size, const u32 _adr, const u32 val) +{ + //printf("%08lld -- write_dma: %d %d %08X %08X\n",nds_timer,proc,size,_adr,val); + const u32 adr = _adr - _REG_DMA_CONTROL_MIN; + const u32 chan = adr/12; + const u32 regnum = (adr - chan*12)>>2; + + if(proc==1) { + int zzz=9; } - if (MMU.DMAStartTime[proc][dmanum] == EDMAMode_GXFifo) + MMU_new.dma[proc][chan].regs[regnum]->write(size,adr,val); +} + + +//this could be inlined... +u32 MMU_struct_new::read_dma(const int proc, const int size, const u32 _adr) +{ + const u32 adr = _adr - _REG_DMA_CONTROL_MIN; + const u32 chan = adr/12; + const u32 regnum = (adr - chan*12)>>2; + + const u32 temp = MMU_new.dma[proc][chan].regs[regnum]->read(size,adr); + //printf("%08lld -- read_dma: %d %d %08X = %08X\n",nds_timer,proc,size,_adr,temp); + + + + if(temp == 0xAF00 && size == 16) { -#ifdef _3DINFO - INFO("ARM%c: DMA%d control src=0x%08X dst=0x%08X %s (gxFIFO tail %03i)\n", (proc==0)?'9':'7', dmanum, DMASrc[proc][dmanum], DMADst[proc][dmanum], ((val>>15)&0x01)?"ON":"OFF", gxFIFO.tail); + int zzz=9; + } + + return temp; +} + +MMU_struct_new::MMU_struct_new() +{ + for(int i=0;i<2;i++) + for(int j=0;j<4;j++) { + dma[i][j].procnum = i; + dma[i][j].chan = j; + } +} + +bool DmaController::loadstate(EMUFILE* f) +{ + u32 version; + if(read32le(&version,f) != 1) return false; + if(version != 0) return false; + + read8le(&enable,f); read8le(&irq,f); read8le(&repeatMode,f); read8le(&_startmode,f); + read8le(&userEnable,f); + read32le(&wordcount,f); + readle(&startmode,f); + readle(&bitWidth,f); + readle(&sar,f); + readle(&dar,f); + read32le(&saddr,f); read32le(&daddr,f); + read32le(&check,f); read32le(&running,f); read32le(&paused,f); read32le(&triggered,f); + read64le(&nextEvent,f); + + return true; +} + +void DmaController::savestate(EMUFILE *f) +{ + write32le(0,f); //version + write8le(enable,f); write8le(irq,f); write8le(repeatMode,f); write8le(_startmode,f); + write8le(userEnable,f); + write32le(wordcount,f); + write8le(startmode,f); + write8le(bitWidth,f); + write8le(sar,f); + write8le(dar,f); + write32le(saddr,f); write32le(daddr,f); + write32le(check,f); write32le(running,f); write32le(paused,f); write32le(triggered,f); + write64le(nextEvent,f); +} + +void DmaController::write32(const u32 val) +{ + if(running) + { + //desp triggers this a lot. figure out whats going on + //printf("thats weird..user edited dma control while it was running\n"); + } + //printf("dma %d,%d WRITE %08X\n",procnum,chan,val); + wordcount = val&0x1FFFFF; + if(wordcount==0x9FbFC || wordcount == 0x1FFFFC || wordcount == 0x1EFFFC || wordcount == 0x1FFFFF) { + int zzz=9; + } + u8 wasRepeatMode = repeatMode; + u8 wasEnable = enable; + u32 valhi = val>>16; + dar = (EDMADestinationUpdate)((valhi>>5)&3); + sar = (EDMASourceUpdate)((valhi>>7)&3); + repeatMode = BIT9(valhi); + bitWidth = (EDMABitWidth)BIT10(valhi); + _startmode = (valhi>>11)&7; + if(procnum==ARMCPU_ARM7) _startmode &= 6; + irq = BIT14(valhi); + enable = BIT15(valhi); + + if(val==0x84400076 && saddr ==0x023BCEC4) + { + int zzz=9; + } + + //if(irq) printf("!!!!!!!!!!!!IRQ!!!!!!!!!!!!!\n"); + + //make sure we don't get any old triggers + if(!wasEnable && enable) + triggered = FALSE; + + //printf("dma %d,%d set to startmode %d with wordcount set to: %08X\n",procnum,chan,_startmode,wordcount); +if(_startmode==0 && wordcount==1) { + int zzz=9; +} + if(enable) + { + int zzz=9; + } + + //analyze enabling and startmode. + //note that we only do this if the dma was freshly enabled. + //we should probably also only be latching these other regs in that case too.. + //but for now just this one will do (otherwise the dma repeat stop procedure (in this case the ff4 title menu load with gamecard dma) will fail) + //if(!running) enable = userEnable; + + //if we were previously in a triggered mode, and were already enabled, + //then don't re-trigger now. this is rather confusing.. + //we really only want to auto-trigger gxfifo and immediate modes. + //but we don't know what mode we're in yet. + //so this is our workaround + //(otherwise the dma repeat stop procedure (in this case the ff4 title menu load with gamecard dma) will fail) + bool doNotStart = false; + if(startmode != EDMAMode_Immediate && startmode != EDMAMode_GXFifo && wasEnable) doNotStart = true; + + //this dma may need to trigger now, so give it a chance + //if(!(wasRepeatMode && !repeatMode)) //this was an older test + if(!doNotStart) + doSchedule(); + + //todo - make a driver stub for this so that we dont have to conditionalize it everywhere +#ifdef WIN32 + RefreshAllIORegViews(); #endif - MMU_doDMA(dmanum); - } -#else - if(MMU.DMAStartTime[proc][dmanum] == EDMAMode_Immediate - || MMU.DMAStartTime[proc][dmanum] == EDMAMode_GXFifo) +} + +void DmaController::exec() +{ + check = FALSE; + + if(running) { - MMU_doDMA(dmanum); + switch(startmode) { + case EDMAMode_GXFifo: + //this dma mode won't finish always its job when it gets signalled + //sometimes it will have words left to transfer. + //if(!paused) printf("gxfifo dma ended with %d remaining\n",wordcount); //only print this once + if(wordcount>0) { + doPause(); + goto start; + } + else doStop(); + break; + default: + doStop(); + } } + else if(enable) + { +start: + //analyze startmode (this only gets latched when a dma begins) + if(procnum==ARMCPU_ARM9) startmode = (EDMAMode)_startmode; + else { + //arm7 startmode analysis: + static const EDMAMode lookup[] = {EDMAMode_Immediate,EDMAMode_VBlank,EDMAMode_Card,EDMAMode7_Wifi}; + //arm7 has a slightly different startmode encoding + startmode = lookup[_startmode>>1]; + if(startmode == EDMAMode7_Wifi && (chan==1 || chan==3)) + startmode = EDMAMode7_GBASlot; + } + + //make it run, if it is triggered + //but first, scan for triggering conditions + switch(startmode) { + case EDMAMode_Immediate: + triggered = TRUE; + break; + case EDMAMode_GXFifo: + if(gxFIFO.size<=127) + triggered = TRUE; + break; + } + + if(triggered) + { + //if(procnum==0) printf("%08lld trig type %d dma#%d with words %d at src:%08X dst:%08X gxf:%d",nds_timer,startmode,chan,wordcount,saddr,daddr,gxFIFO.size); + if(saddr ==0x023BCCEC && wordcount==118) { + int zzz=9; + } + if(startmode==0 && daddr == 0x4000400) { + int zzz=9; + } + running = TRUE; + paused = FALSE; + doCopy(); + //printf(";%d\n",gxFIFO.size); + } + } + +#ifdef WIN32 + RefreshAllIORegViews(); #endif +} - DMALOG("ARM%c: DMA%d control src=0x%08X dst=0x%08X %s\n", (proc==0)?'9':'7', dmanum, DMASrc[proc][dmanum], DMADst[proc][dmanum], ((val>>15)&0x01)?"ON":"OFF"); +void DmaController::doCopy() +{ + //generate a copy count depending on various copy mode's behavior + u32 todo = wordcount; + if(todo == 0) todo = 0x200000; //according to gbatek.. //TODO - this should not work this way for arm7 according to gbatek + if(startmode == EDMAMode_MemDisplay) todo = 128; //this is a hack. maybe an alright one though. it should be 4 words at a time. this is a whole scanline + if(startmode == EDMAMode_Card) todo *= 0x80; + if(startmode == EDMAMode_GXFifo) todo = std::min(wordcount,(u32)112); + //determine how we're going to copy + bool bogarted = false; + u32 sz = (bitWidth==EDMABitWidth_16)?2:4; + u32 dstinc,srcinc; + switch(dar) { + case EDMADestinationUpdate_Increment : dstinc = sz; break; + case EDMADestinationUpdate_Decrement : dstinc = (u32)-(s32)sz; break; + case EDMADestinationUpdate_Fixed : dstinc = 0; break; + case EDMADestinationUpdate_IncrementReload : dstinc = sz; break; + default: bogarted = true; break; + } + switch(sar) { + case EDMASourceUpdate_Increment : srcinc = sz; break; + case EDMASourceUpdate_Decrement : srcinc = (u32)-(s32)sz; break; + case EDMASourceUpdate_Fixed : srcinc = 0; break; + case EDMASourceUpdate_Invalid : bogarted = true; break; + default: bogarted = true; break; + } + + //need to figure out what to do about this + if(bogarted) + { + printf("YOUR GAME IS BOGARTED!!! PLEASE REPORT!!!\n"); + assert(false); + return; + } + + u32 src = saddr; + u32 dst = daddr; + + //if these do not use MMU_AT_DMA and the corresponding code in the read/write routines, + //then danny phantom title screen will be filled with a garbage char which is made by + //dmaing from 0x00000000 to 0x06000000 + //TODO - these might be losing out a lot by not going through the templated version anymore. + //we might make another function to do just the raw copy op which can use them with checks + //outside the loop + if(sz==4) { + for(s32 i=(s32)todo; i>0; i--) + { + u32 temp = _MMU_read32(procnum,MMU_AT_DMA,src); + if(startmode == EDMAMode_GXFifo) { + //printf("GXFIFO DMA OF %08X FROM %08X WHILE GXFIFO.SIZE=%d\n",temp,src,gxFIFO.size); + } + _MMU_write32(procnum,MMU_AT_DMA,dst, temp); + dst += dstinc; + src += srcinc; + } + } else { + for(s32 i=(s32)todo; i>0; i--) + { + _MMU_write16(procnum,MMU_AT_DMA,dst, _MMU_read16(procnum,MMU_AT_DMA,src)); + dst += dstinc; + src += srcinc; + } + } + + //reschedule an event for the end of this dma, and figure out how much it cost us + doSchedule(); + nextEvent += todo/4; //TODO - surely this is a gross simplification + //apparently moon has very, very tight timing (i didnt spy it using waitbyloop swi...) + //so lets bump this down a bit for now, + //(i think this code is in nintendo libraries) + + //write back the addresses + saddr = src; + if(dar != EDMADestinationUpdate_IncrementReload) //but dont write back dst if we were supposed to reload + daddr = dst; + + //do wordcount accounting + if(startmode == EDMAMode_Card) + todo /= 0x80; //divide this funky one back down before subtracting it + + if(!repeatMode) + wordcount -= todo; +} + +void triggerDma(EDMAMode mode) +{ + for(int i=0;i<2;i++) for(int j=0;j<4;j++) MMU_new.dma[i][j].tryTrigger(mode); +} + +void DmaController::tryTrigger(EDMAMode mode) +{ + if(startmode != mode) return; + + //hmm dont trigger it if its already running! + //but paused things need triggers to continue + if(running && !paused) return; + triggered = TRUE; + doSchedule(); +} + +void DmaController::doSchedule() +{ + check = TRUE; + nextEvent = nds_timer; NDS_RescheduleDMA(); } + +void DmaController::doPause() +{ + triggered = FALSE; + paused = TRUE; +} + +void DmaController::doStop() +{ + //if(procnum==0) printf("%08lld stop type %d dma#%d\n",nds_timer,startmode,chan); + running = FALSE; + if(!repeatMode) enable = FALSE; + if(irq) { + if(procnum==0) NDS_makeARM9Int(8+chan); + else NDS_makeARM7Int(8+chan); + } +} + + + +u32 DmaController::read32() +{ + u32 ret = 0; + ret |= enable<<31; + ret |= irq<<30; + ret |= _startmode<<27; + ret |= bitWidth<<26; + ret |= repeatMode<<25; + ret |= sar<<23; + ret |= dar<<21; + ret |= wordcount; + //printf("dma %d,%d READ %08X\n",procnum,chan,ret); + if(ret == 0xAF000001) { + int zzz=9; + } + return ret; +} + 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... @@ -1808,6 +2260,8 @@ void FASTCALL _MMU_ARM9_write08(u32 adr, u8 val) if (adr >> 24 == 4) { + if(MMU_new.is_dma(adr)) { MMU_new.write_dma(ARMCPU_ARM9,8,adr,val); return; } + switch(adr) { case REG_DISPA_DISP3DCNT: @@ -1826,6 +2280,10 @@ void FASTCALL _MMU_ARM9_write08(u32 adr, u8 val) break; } + case eng_3D_GXSTAT: + MMU_new.gxstat.write(8,adr,val); + break; + case REG_DISPA_WIN0H: GPU_setWIN0_H1(MainScreen.gpu, val); break ; @@ -1982,6 +2440,7 @@ void FASTCALL _MMU_ARM9_write08(u32 adr, u8 val) case 0x040001AF : LOG("%08X : %02X\r\n", adr, val); #endif + } MMU.MMU_MEM[ARMCPU_ARM9][0x40][adr&MMU.MMU_MASK[ARMCPU_ARM9][adr>>20]]=val; @@ -2017,6 +2476,14 @@ void FASTCALL _MMU_ARM9_write16(u32 adr, u16 val) if((adr >> 24) == 4) { + if(MMU_new.is_dma(adr)) { + if(val==0x02e9) { + int zzz=9; + } + MMU_new.write_dma(ARMCPU_ARM9,16,adr,val); + return; + } + switch (adr >> 4) { //toon table @@ -2031,6 +2498,10 @@ void FASTCALL _MMU_ARM9_write16(u32 adr, u16 val) // Address is an IO register switch(adr) { + case eng_3D_GXSTAT: + MMU_new.gxstat.write(16,adr,val); + break; + case REG_DISPA_BG2XL: MainScreen.gpu->setAffineStartWord(2,0,val,0); break; case REG_DISPA_BG2XH: MainScreen.gpu->setAffineStartWord(2,0,val,1); break; case REG_DISPA_BG2YL: MainScreen.gpu->setAffineStartWord(2,1,val,0); break; @@ -2371,10 +2842,12 @@ void FASTCALL _MMU_ARM9_write16(u32 adr, u16 val) case REG_IF : NDS_Reschedule(); MMU.reg_IF[ARMCPU_ARM9] &= (~((u32)val)); + validateIF_arm9(); return; case REG_IF + 2 : NDS_Reschedule(); MMU.reg_IF[ARMCPU_ARM9] &= (~(((u32)val)<<16)); + validateIF_arm9(); return; case REG_IPCSYNC : @@ -2445,18 +2918,6 @@ void FASTCALL _MMU_ARM9_write16(u32 adr, u16 val) return; } - case REG_DMA0CNTH : - write_dma_hictrl(0,val); - return; - case REG_DMA1CNTH : - write_dma_hictrl(1,val); - return; - case REG_DMA2CNTH : - write_dma_hictrl(2,val); - return; - case REG_DMA3CNTH : - write_dma_hictrl(3,val); - return; case REG_DISPA_DISPMMEMFIFO: { DISP_FIFOsend(val); @@ -2468,6 +2929,12 @@ void FASTCALL _MMU_ARM9_write16(u32 adr, u16 val) return; } + if(adr>=0x05000000 && adr<0x06000000) + { + int zzz=9; + } + + bool unmapped; adr = MMU_LCDmap(adr, unmapped); if(unmapped) return; @@ -2493,6 +2960,11 @@ void FASTCALL _MMU_ARM9_write32(u32 adr, u32 val) return; } + if((adr&0x0F000000)==0x05000000) + { + int zzz=9; + } + adr &= 0x0FFFFFFF; #if 0 @@ -2570,8 +3042,13 @@ void FASTCALL _MMU_ARM9_write32(u32 adr, u32 val) break; } + if(MMU_new.is_dma(adr)) { MMU_new.write_dma(ARMCPU_ARM9,32,adr,val); return; } + switch(adr) { + case eng_3D_GXSTAT: + MMU_new.gxstat.write32(val); + break; case REG_DISPA_BG2XL: MainScreen.gpu->setAffineStart(2,0,val); return; @@ -2597,10 +3074,6 @@ void FASTCALL _MMU_ARM9_write32(u32 adr, u32 val) SubScreen.gpu->setAffineStart(3,1,val); return; - case 0x04000600: - GFX_FIFOcnt(val); - return; - // Alpha test reference value - Parameters:1 case 0x04000340: { @@ -2763,6 +3236,7 @@ void FASTCALL _MMU_ARM9_write32(u32 adr, u32 val) case REG_IF : NDS_Reschedule(); MMU.reg_IF[ARMCPU_ARM9] &= (~val); + validateIF_arm9(); return; case REG_TM0CNTL: @@ -2810,23 +3284,8 @@ void FASTCALL _MMU_ARM9_write32(u32 adr, u32 val) IPC_FIFOsend(ARMCPU_ARM9, val); return; - case REG_DMA0CNTL : - T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0xB8, val); //write the low word - write_dma_hictrl(0,val>>16); - return; - case REG_DMA1CNTL: - T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0xC4, val); //write the low word - write_dma_hictrl(1,val>>16); - return; - case REG_DMA2CNTL : - T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0xD0, val); //write the low word - write_dma_hictrl(2,val>>16); - return; - case REG_DMA3CNTL : - T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0xDC, val); //write the low word - write_dma_hictrl(3,val>>16); - return; - case REG_GCROMCTRL : + + case REG_GCROMCTRL : MMU_writeToGCControl(val); return; case REG_DISPA_DISPCAPCNT : @@ -2866,6 +3325,10 @@ void FASTCALL _MMU_ARM9_write32(u32 adr, u32 val) T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], adr & MMU.MMU_MASK[ARMCPU_ARM9][adr>>20], val); return; } + if(adr>=0x05000000 && adr<0x06200000) + { + int zzz=9; + } bool unmapped; adr = MMU_LCDmap(adr, unmapped); @@ -2886,6 +3349,20 @@ u8 FASTCALL _MMU_ARM9_read08(u32 adr) if ( (adr >= 0x08000000) && (adr < 0x0A010000) ) return addon.read08(adr); + adr &= 0x0FFFFFFF; + + if (adr >> 24 == 4) + { //Address is an IO register + + if(MMU_new.is_dma(adr)) return MMU_new.read_dma(ARMCPU_ARM9,8,adr); + + switch(adr) + { + case eng_3D_GXSTAT: + return MMU_new.gxstat.read(8,adr); + } + } + bool unmapped; adr = MMU_LCDmap(adr, unmapped); if(unmapped) return 0; @@ -2908,14 +3385,23 @@ u16 FASTCALL _MMU_ARM9_read16(u32 adr) if (adr >> 24 == 4) { + if(MMU_new.is_dma(adr)) return MMU_new.read_dma(ARMCPU_ARM9,16,adr); + // Address is an IO register switch(adr) { + case eng_3D_GXSTAT: + return MMU_new.gxstat.read(16,adr); + // ============================================= 3D - case 0x04000604: - return (gfx3d_GetNumPolys()); - case 0x04000606: - return (gfx3d_GetNumVertex()); + case eng_3D_RAM_COUNT: + return 0; + //almost worthless for now + //return (gfx3d_GetNumPolys()); + case eng_3D_RAM_COUNT+2: + return 0; + //almost worthless for now + //return (gfx3d_GetNumVertex()); case 0x04000630: case 0x04000632: case 0x04000634: @@ -2951,6 +3437,7 @@ u16 FASTCALL _MMU_ARM9_read16(u32 adr) case REG_POSTFLG : return 1; + } return T1ReadWord_guaranteedAligned(MMU.MMU_MEM[ARMCPU_ARM9][0x40], adr & MMU.MMU_MASK[ARMCPU_ARM9][adr >> 20]); @@ -2980,6 +3467,8 @@ u32 FASTCALL _MMU_ARM9_read32(u32 adr) // Address is an IO register if((adr >> 24) == 4) { + if(MMU_new.is_dma(adr)) return MMU_new.read_dma(ARMCPU_ARM9,32,adr); + switch(adr) { case 0x04000640: @@ -3029,7 +3518,10 @@ u32 FASTCALL _MMU_ARM9_read32(u32 adr) { return gfx3d_glGetPosRes((adr & 0xF) >> 2); } + case eng_3D_GXSTAT: + return MMU_new.gxstat.read(32,adr); // ======================================== 3D end + case REG_IME : return MMU.reg_IME[ARMCPU_ARM9]; @@ -3116,6 +3608,8 @@ void FASTCALL _MMU_ARM7_write08(u32 adr, u8 val) if (adr >> 24 == 4) { + if(MMU_new.is_dma(adr)) { MMU_new.write_dma(ARMCPU_ARM7,8,adr,val); return; } + switch(adr) { case REG_RTC: @@ -3152,7 +3646,7 @@ void FASTCALL _MMU_ARM7_write16(u32 adr, u16 val) #ifdef EXPERIMENTAL_WIFI - /* wifi mac access */ + //wifi mac access if ((adr>=0x04800000)&&(adr<0x05000000)) { WIFI_write16(adr,val); @@ -3174,7 +3668,9 @@ void FASTCALL _MMU_ARM7_write16(u32 adr, u16 val) if((adr >> 24) == 4) { - /* Address is an IO register */ + if(MMU_new.is_dma(adr)) { MMU_new.write_dma(ARMCPU_ARM7,16,adr,val); return; } + + //Address is an IO register switch(adr) { case REG_RTC: @@ -3429,18 +3925,6 @@ void FASTCALL _MMU_ARM7_write16(u32 adr, u16 val) return; } - case REG_DMA0CNTH : - write_dma_hictrl(0,val); - return; - case REG_DMA1CNTH : - write_dma_hictrl(1,val); - return; - case REG_DMA2CNTH : - write_dma_hictrl(2,val); - return; - case REG_DMA3CNTH : - write_dma_hictrl(3,val); - return; } T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM7][0x40], adr&MMU.MMU_MASK[ARMCPU_ARM7][adr>>20], val); @@ -3488,6 +3972,8 @@ void FASTCALL _MMU_ARM7_write32(u32 adr, u32 val) if((adr>>24)==4) { + if(MMU_new.is_dma(adr)) { MMU_new.write_dma(ARMCPU_ARM7,32,adr,val); return; } + switch(adr) { case REG_RTC: @@ -3557,23 +4043,6 @@ void FASTCALL _MMU_ARM7_write32(u32 adr, u32 val) IPC_FIFOsend(ARMCPU_ARM7, val); return; - case REG_DMA0CNTL : - T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0xB8, val); //write the low word - write_dma_hictrl(0,val>>16); - return; - case REG_DMA1CNTL: - T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0xC4, val); //write the low word - write_dma_hictrl(1,val>>16); - return; - case REG_DMA2CNTL : - T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0xD0, val); //write the low word - write_dma_hictrl(2,val>>16); - return; - case REG_DMA3CNTL : - T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0xDC, val); //write the low word - write_dma_hictrl(3,val>>16); - return; - case REG_GCROMCTRL : MMU_writeToGCControl(val); return; @@ -3611,6 +4080,14 @@ u8 FASTCALL _MMU_ARM7_read08(u32 adr) if (adr == REG_RTC) return (u8)rtcRead(); + if (adr >> 24 == 4) + { + if(MMU_new.is_dma(adr)) return MMU_new.read_dma(ARMCPU_ARM7,8,adr); + + // Address is an IO register + //switch(adr) {} + } + bool unmapped; adr = MMU_LCDmap(adr,unmapped); if(unmapped) return 0; @@ -3623,7 +4100,7 @@ u16 FASTCALL _MMU_ARM7_read16(u32 adr) mmu_log_debug_ARM7(adr, "(read16) %0x%X", T1ReadWord(MMU.MMU_MEM[ARMCPU_ARM7][(adr >> 20) & 0xFF], adr & MMU.MMU_MASK[ARMCPU_ARM7][(adr >> 20) & 0xFF])); #ifdef EXPERIMENTAL_WIFI - /* wifi mac access */ + //wifi mac access if ((adr>=0x04800000)&&(adr<0x05000000)) return WIFI_read16(adr) ; #endif @@ -3634,8 +4111,10 @@ u16 FASTCALL _MMU_ARM7_read16(u32 adr) adr &= 0x0FFFFFFE; if(adr>>24==4) - { - /* Address is an IO register */ + { //Address is an IO register + + if(MMU_new.is_dma(adr)) return MMU_new.read_dma(ARMCPU_ARM7,16,adr); + switch(adr) { case REG_RTC: @@ -3663,14 +4142,14 @@ u16 FASTCALL _MMU_ARM7_read16(u32 adr) case REG_AUXSPICNT: return MMU.AUX_SPI_CNT; - case 0x04000130: - case 0x04000136: + case REG_KEYINPUT: + case REG_EXTKEYIN: //here is an example of what not to do: //since the arm7 polls this every frame, we shouldnt count this as an input check //LagFrameFlag=0; break; - - case REG_POSTFLG : + + case REG_POSTFLG: return 1; } return T1ReadWord_guaranteedAligned(MMU.MMU_MEM[ARMCPU_ARM7][adr >> 20], adr & MMU.MMU_MASK[ARMCPU_ARM7][adr >> 20]); @@ -3690,7 +4169,7 @@ u32 FASTCALL _MMU_ARM7_read32(u32 adr) mmu_log_debug_ARM7(adr, "(read32) %0x%X", T1ReadWord(MMU.MMU_MEM[ARMCPU_ARM7][(adr >> 20) & 0xFF], adr & MMU.MMU_MASK[ARMCPU_ARM7][(adr >> 20) & 0xFF])); #ifdef EXPERIMENTAL_WIFI - /* wifi mac access */ + //wifi mac access if ((adr>=0x04800000)&&(adr<0x05000000)) return (WIFI_read16(adr) | (WIFI_read16(adr+2) << 16)); #endif @@ -3701,8 +4180,10 @@ u32 FASTCALL _MMU_ARM7_read32(u32 adr) adr &= 0x0FFFFFFC; if((adr >> 24) == 4) - { - /* Address is an IO register */ + { //Address is an IO register + + if(MMU_new.is_dma(adr)) return MMU_new.read_dma(ARMCPU_ARM7,32,adr); + switch(adr) { case REG_RTC: @@ -3731,6 +4212,7 @@ u32 FASTCALL _MMU_ARM7_read32(u32 adr) } case REG_GCDATAIN: return MMU_readFromGC(); + } return T1ReadLong_guaranteedAligned(MMU.MMU_MEM[ARMCPU_ARM7][(adr >> 20)], adr & MMU.MMU_MASK[ARMCPU_ARM7][(adr >> 20)]); } diff --git a/desmume/src/MMU.h b/desmume/src/MMU.h index d62c888be..c9e190767 100644 --- a/desmume/src/MMU.h +++ b/desmume/src/MMU.h @@ -27,8 +27,9 @@ #include "FIFO.h" #include "mem.h" - +#include "registers.h" #include "mc.h" +#include "bits.h" #define ARMCPU_ARM7 1 #define ARMCPU_ARM9 0 @@ -36,6 +37,195 @@ typedef const u8 TWaitState; + +enum EDMAMode : u8 +{ + 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, +}; + +enum EDMABitWidth : u8 +{ + EDMABitWidth_16 = 0, + EDMABitWidth_32 = 1 +}; + +enum EDMASourceUpdate : u8 +{ + EDMASourceUpdate_Increment = 0, + EDMASourceUpdate_Decrement = 1, + EDMASourceUpdate_Fixed = 2, + EDMASourceUpdate_Invalid = 3, +}; + +enum EDMADestinationUpdate : u8 +{ + EDMADestinationUpdate_Increment = 0, + EDMADestinationUpdate_Decrement = 1, + EDMADestinationUpdate_Fixed = 2, + EDMADestinationUpdate_IncrementReload = 3, +}; + + +class TRegister_32 +{ +public: + virtual u32 read32() = 0; + virtual void write32(const u32 val) = 0; + void write(const int size, const u32 adr, const u32 val) { + if(size==32) write32(val); + else { + const u32 offset = adr&3; + const u32 baseaddr = adr&~offset; + if(size==8) { + printf("WARNING! 8BIT DMA ACCESS\n"); + u32 mask = 0xFF<<(offset<<3); + write32((read32()&~mask)|(val<<(offset<<3))); + } + else if(size==16) { + u32 mask = 0xFFFF<<(offset<<3); + write32((read32()&~mask)|(val<<(offset<<3))); + } + } + } + + u32 read(const int size, const u32 adr) + { + if(size==32) return read32(); + else { + const u32 offset = adr&3; + const u32 baseaddr = adr&~offset; + if(size==8) { printf("WARNING! 8BIT DMA ACCESS\n"); return (read32()>>(offset<<3))&0xFF; } + else return (read32()>>(offset<<3))&0xFFFF; + } + } +}; + +struct TGXSTAT : public TRegister_32 +{ + TGXSTAT() { + gxfifo_irq = se = tr = tb = 0; + } + u8 tb; //test busy + u8 tr; //test result + u8 se; //stack error + u8 gxfifo_irq; //irq configuration + + + virtual u32 read32(); + virtual void write32(const u32 val); + + void savestate(EMUFILE *f); + bool loadstate(EMUFILE *f); +}; + +void triggerDma(EDMAMode mode); + +class DmaController +{ +public: + u8 enable, irq, repeatMode, _startmode; + u8 userEnable; + u32 wordcount; + EDMAMode startmode; + EDMABitWidth bitWidth; + EDMASourceUpdate sar; + EDMADestinationUpdate dar; + u32 saddr, daddr; + + //indicates whether the dma needs to be checked for triggering + BOOL check; + + //indicates whether the dma right now is logically running + //(though for now we copy all the data when it triggers) + BOOL running; + + BOOL paused; + + //this flag will sometimes be set when a start condition is triggered + //other conditions may be automatically triggered based on scanning conditions + BOOL triggered; + + u64 nextEvent; + + int procnum, chan; + + void savestate(EMUFILE *f); + bool loadstate(EMUFILE *f); + + void exec(); + void doCopy(); + void doPause(); + void doStop(); + void doSchedule(); + void tryTrigger(EDMAMode mode); + + DmaController() : + enable(0), irq(0), bitWidth(EDMABitWidth_16), repeatMode(0), _startmode(0), + sar(EDMASourceUpdate_Increment), dar(EDMADestinationUpdate_Increment), + wordcount(0), startmode(EDMAMode_Immediate), + sad(&saddr), + dad(&daddr), + check(FALSE), + running(FALSE), + paused(FALSE), + triggered(FALSE), + nextEvent(0) + { + sad.controller = this; + dad.controller = this; + ctrl.controller = this; + regs[0] = &sad; + regs[1] = &dad; + regs[2] = &ctrl; + } + + class AddressRegister : public TRegister_32 { + public: + //we pass in a pointer to the controller here so we can alert it if anything changes + DmaController* controller; + u32 * const ptr; + AddressRegister(u32* _ptr) + : ptr(_ptr) + {} + virtual u32 read32() { + return *ptr; + } + virtual void write32(const u32 val) { + *ptr = val; + } + }; + + class ControlRegister : public TRegister_32 { + public: + //we pass in a pointer to the controller here so we can alert it if anything changes + DmaController* controller; + ControlRegister() {} + virtual u32 read32() { + return controller->read32(); + } + virtual void write32(const u32 val) { + return controller->write32(val); + } + }; + + AddressRegister sad, dad; + ControlRegister ctrl; + TRegister_32* regs[3]; + + void write32(const u32 val); + u32 read32(); + +}; + enum ECardMode { CardMode_Normal = 0, @@ -168,9 +358,17 @@ struct MMU_struct u32 CheckDMAs; }; +//this contains things which can't be memzeroed because they are smarter classes struct MMU_struct_new { + MMU_struct_new() ; BackupDevice backupDevice; + DmaController dma[2][4]; + TGXSTAT gxstat; + + void write_dma(const int proc, const int size, const u32 adr, const u32 val); + u32 read_dma(const int proc, const int size, const u32 adr); + bool is_dma(const u32 adr) { return adr >= _REG_DMA_CONTROL_MIN && adr <= _REG_DMA_CONTROL_MAX; } }; extern MMU_struct MMU; @@ -220,7 +418,7 @@ void FASTCALL MMU_write8(u32 proc, u32 adr, u8 val); void FASTCALL MMU_write16(u32 proc, u32 adr, u16 val); void FASTCALL MMU_write32(u32 proc, u32 adr, u32 val); -template void FASTCALL MMU_doDMA(u32 num); +//template void FASTCALL MMU_doDMA(u32 num); //The base ARM memory interfaces extern struct armcpu_memory_iface arm9_base_memory_iface; @@ -343,20 +541,6 @@ 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 diff --git a/desmume/src/NDSSystem.cpp b/desmume/src/NDSSystem.cpp index 86a07887f..483e41506 100644 --- a/desmume/src/NDSSystem.cpp +++ b/desmume/src/NDSSystem.cpp @@ -1492,22 +1492,6 @@ void NDS_SkipNextFrame() { #define INDEX(i) ((((i)>>16)&0xFF0)|(((i)>>4)&0xF)) -static 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 { @@ -1555,22 +1539,15 @@ struct TSequenceItem_GXFIFO : public TSequenceItem { FORCEINLINE bool isTriggered() { - #ifndef USE_GEOMETRY_FIFO_EMULATION - return false; - #else - return enabled && nds_timer >= MMU.gfx3dCycles; - #endif + return enabled && nds_timer >= MMU.gfx3dCycles; } FORCEINLINE void exec() { - #ifdef USE_GEOMETRY_FIFO_EMULATION - enabled = false; //do this first, because gfx3d_execute3D() will cause more scheduled events if necessary + while(isTriggered()) { + enabled = false; 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() @@ -1651,30 +1628,57 @@ template struct TSequenceItem_Timer : public TSequenceItem template struct TSequenceItem_DMA : public TSequenceItem { + DmaController* controller; + FORCEINLINE bool isTriggered() { - return (MMU.DMAing[procnum][chan])&&nds_timer>=(MMU.DMACycle[procnum][chan]); + return (controller->check && nds_timer>= controller->nextEvent); } - FORCEINLINE bool isEnabled() { return MMU.DMAing[procnum][chan]!=0; } + FORCEINLINE bool isEnabled() { + return controller->check?TRUE:FALSE; + } FORCEINLINE u64 next() { - return MMU.DMACycle[procnum][chan]; + return controller->nextEvent; } FORCEINLINE void exec() { - if (MMU.DMACompleted[procnum][chan]) - { - u8* regs = procnum==0?MMU.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; - } + //printf("exec from TSequenceItem_DMA: %d %d\n",procnum,chan); + controller->exec(); +// //give gxfifo dmas a chance to re-trigger +// if(MMU.DMAStartTime[procnum][chan] == EDMAMode_GXFifo) { +// MMU.DMAing[procnum][chan] = FALSE; +// if (gxFIFO.size <= 127) +// { +// execHardware_doDma(procnum,chan,EDMAMode_GXFifo); +// if (MMU.DMACompleted[procnum][chan]) +// goto docomplete; +// else return; +// } +// } +// +//docomplete: +// if (MMU.DMACompleted[procnum][chan]) +// { +// u8* regs = procnum==0?MMU.ARM9_REG:MMU.ARM7_REG; +// +// //disable the channel +// if(MMU.DMAStartTime[procnum][chan] != EDMAMode_GXFifo) { +// T1WriteLong(regs, 0xB8 + (0xC*chan), T1ReadLong(regs, 0xB8 + (0xC*chan)) & 0x7FFFFFFF); +// MMU.DMACrt[procnum][chan] &= 0x7FFFFFFF; //blehhh i hate this shit being mirrored in memory +// } +// +// if((MMU.DMACrt[procnum][chan])&(1<<30)) { +// if(procnum==0) NDS_makeARM9Int(8+chan); +// else NDS_makeARM7Int(8+chan); +// } +// +// MMU.DMAing[procnum][chan] = FALSE; +// } + } }; @@ -1790,12 +1794,14 @@ struct Sequencer } sequencer; -void NDS_RescheduleGXFIFO() +void NDS_RescheduleGXFIFO(u32 cost) { -#ifdef USE_GEOMETRY_FIFO_EMULATION - sequencer.gxfifo.enabled = true; + if(!sequencer.gxfifo.enabled) { + MMU.gfx3dCycles = nds_timer; + sequencer.gxfifo.enabled = true; + } + MMU.gfx3dCycles += cost; NDS_Reschedule(); -#endif } void NDS_RescheduleTimers() @@ -1812,6 +1818,7 @@ void NDS_RescheduleDMA() { //TBD NDS_Reschedule(); + } static void initSchedule() @@ -1850,6 +1857,15 @@ void Sequencer::init() gxfifo.enabled = false; + dma_0_0.controller = &MMU_new.dma[0][0]; + dma_0_1.controller = &MMU_new.dma[0][1]; + dma_0_2.controller = &MMU_new.dma[0][2]; + dma_0_3.controller = &MMU_new.dma[0][3]; + dma_1_0.controller = &MMU_new.dma[1][0]; + dma_1_1.controller = &MMU_new.dma[1][1]; + dma_1_2.controller = &MMU_new.dma[1][2]; + dma_1_3.controller = &MMU_new.dma[1][3]; + #ifdef EXPERIMENTAL_WIFI wifi.enabled = true; @@ -1891,7 +1907,7 @@ static void execHardware_hblank() //trigger hblank dmas //but notice, we do that just after we finished drawing the line //(values copied by this hdma should not be used until the next scanline) - execHardware_doAllDma(EDMAMode_HBlank); + triggerDma(EDMAMode_HBlank); } } @@ -1908,6 +1924,8 @@ static void execHardware_hstart_vblankEnd() static void execHardware_hstart_vblankStart() { + //printf("--------VBLANK!!!--------\n"); + //turn on vblank status bit T1WriteWord(MMU.ARM9_REG, 4, T1ReadWord(MMU.ARM9_REG, 4) | 1); T1WriteWord(MMU.ARM7_REG, 4, T1ReadWord(MMU.ARM7_REG, 4) | 1); @@ -1927,7 +1945,7 @@ static void execHardware_hstart_vblankStart() SkipCur2DFrame = false; //trigger vblank dmas - execHardware_doAllDma(EDMAMode_VBlank); + triggerDma(EDMAMode_VBlank); } static void execHardware_hstart_vcount() @@ -1979,7 +1997,7 @@ static void execHardware_hstart() execHardware_hstart_vcount(); //trigger hstart dmas - execHardware_doAllDma(EDMAMode_HStart); + triggerDma(EDMAMode_HStart); if(nds.VCount<192) { @@ -1988,7 +2006,7 @@ static void execHardware_hstart() //it should be driven by a fifo (and generate just in time as the scanline is displayed) //but that isnt even possible until we have some sort of sub-scanline timing. //it may not be necessary. - execHardware_doAllDma(EDMAMode_MemDisplay); + triggerDma(EDMAMode_MemDisplay); } //end of 3d vblank @@ -2321,12 +2339,6 @@ void NDS_exec(s32 nb) 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 diff --git a/desmume/src/NDSSystem.h b/desmume/src/NDSSystem.h index ea7255de9..3d64c5c07 100644 --- a/desmume/src/NDSSystem.h +++ b/desmume/src/NDSSystem.h @@ -146,7 +146,7 @@ void emu_halt(); extern u64 nds_timer; void NDS_Reschedule(); -void NDS_RescheduleGXFIFO(); +void NDS_RescheduleGXFIFO(u32 cost); void NDS_RescheduleDMA(); void NDS_RescheduleTimers(); diff --git a/desmume/src/OGLRender.cpp b/desmume/src/OGLRender.cpp index 6f9d937d0..aec84606f 100644 --- a/desmume/src/OGLRender.cpp +++ b/desmume/src/OGLRender.cpp @@ -855,12 +855,12 @@ static void OGLRender() glBegin(GL_TRIANGLES); VERT *vert0 = &gfx3d.vertlist->list[poly->vertIndexes[0]]; - float alpha = poly->getAlpha()/31.0; + float alpha = poly->getAlpha()/31.0f; if(wireframe) alpha = 1.0; float color0[4] = { - (vert0->color[0]<<2)/255.0, - (vert0->color[1]<<2)/255.0, - (vert0->color[2]<<2)/255.0, + (vert0->color[0]<<2)/255.0f, + (vert0->color[1]<<2)/255.0f, + (vert0->color[2]<<2)/255.0f, alpha }; @@ -873,15 +873,15 @@ static void OGLRender() VERT *vert2 = &gfx3d.vertlist->list[poly->vertIndexes[j+1]]; float color1[4] = { - (vert1->color[0]<<2)/255.0, - (vert1->color[1]<<2)/255.0, - (vert1->color[2]<<2)/255.0, + (vert1->color[0]<<2)/255.0f, + (vert1->color[1]<<2)/255.0f, + (vert1->color[2]<<2)/255.0f, alpha }; float color2[4] = { - (vert2->color[0]<<2)/255.0, - (vert2->color[1]<<2)/255.0, - (vert2->color[2]<<2)/255.0, + (vert2->color[0]<<2)/255.0f, + (vert2->color[1]<<2)/255.0f, + (vert2->color[2]<<2)/255.0f, alpha }; diff --git a/desmume/src/addons/gbagame.cpp b/desmume/src/addons/gbagame.cpp index f81f5f8e0..8d3b4d21a 100644 --- a/desmume/src/addons/gbagame.cpp +++ b/desmume/src/addons/gbagame.cpp @@ -141,7 +141,7 @@ static void gbaWriteFlash(u32 adr, u8 val) { u32 ofs = (adr & 0x0000F000); //INFO("GBAgame: Flash: erase from 0x%08X to 0x%08X\n", ofs + 0x0A000000, ofs + 0x0A001000); - for (int i = ofs; i < (ofs + 0x1000); i++) + for (u32 i = ofs; i < (ofs + 0x1000); i++) saveData[i] = 0xFF; } gbaFlash.state = 0; @@ -223,7 +223,7 @@ static u8 getSaveTypeGBA(const u8 *data, const u32 size) u8 type = 0; u8 *dat = (u8 *)data; - for (int i = 0; i < (size / 4); i++) + for (u32 i = 0; i < (size / 4); i++) { u32 tmp = T1ReadLong(dat, i); diff --git a/desmume/src/bios.cpp b/desmume/src/bios.cpp index 7e68b15f3..5852f3746 100644 --- a/desmume/src/bios.cpp +++ b/desmume/src/bios.cpp @@ -24,12 +24,11 @@ #include "MMU.h" #include "SPU.h" #include "debug.h" +#include "NDSSystem.h" #define cpu (&ARMPROC) #define TEMPLATE template -extern BOOL execute; - static const u16 getsinetbl[] = { 0x0000, 0x0324, 0x0648, 0x096A, 0x0C8C, 0x0FAB, 0x12C8, 0x15E2, 0x18F9, 0x1C0B, 0x1F1A, 0x2223, 0x2528, 0x2826, 0x2B1F, 0x2E11, @@ -198,6 +197,7 @@ TEMPLATE static u32 bios_nop() TEMPLATE static u32 WaitByLoop() { + //printf("%lld waitbyloop\n",nds_timer); //INFO("ARM%c: SWI 0x03 (WaitByLoop)\n", PROCNUM?'7':'9'); if (PROCNUM == ARMCPU_ARM9) { diff --git a/desmume/src/gfx3d.cpp b/desmume/src/gfx3d.cpp index 5228f10dd..a504a6635 100644 --- a/desmume/src/gfx3d.cpp +++ b/desmume/src/gfx3d.cpp @@ -25,6 +25,8 @@ //This handles almost all of the work of 3d rendering, leaving the renderer //plugin responsible only for drawing primitives. +//#define FLUSHMODE_HACK + #include #include #include @@ -42,6 +44,8 @@ #include "NDSSystem.h" #include "readwrite.h" #include "FIFO.h" +#include +#include "movie.h" /* thoughts on flush timing: @@ -60,13 +64,200 @@ But since we're not sure how we'll eventually want this, I am leaving it sort of in this function: */ static void gfx3d_doFlush(); -#ifdef USE_GEOMETRY_FIFO_EMULATION -#define GFX_DELAY(x) MMU.gfx3dCycles = nds_timer + (1*x); -#define GFX_DELAY_M2(x) MMU.gfx3dCycles += (1*x); -#else -#define GFX_DELAY(x) -#define GFX_DELAY_M2(x) -#endif +#define INVALID_COMMAND 0xFF +#define UNDEFINED_COMMAND 0xCC +static const u8 gfx3d_commandTypes[] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, //invalid commands; no parameters + 0x01,0x00,0x01,0x01,0x01,0x00,0x10,0x0C, 0x10,0x0C,0x09,0x03,0x03,0xCC,0xCC,0xCC, //matrix commands + 0x01,0x01,0x01,0x02,0x01,0x01,0x01,0x01, 0x01,0x01,0x01,0x01,0xCC,0xCC,0xCC,0xCC, //vertex and per-vertex material commands + 0x01,0x01,0x01,0x01,0x20,0xCC,0xCC,0xCC, 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC, //lighting engine material commands + 0x01,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC, 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC, //begin and end + 0x01,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC, 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC, //swapbuffers + 0x01,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC, 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC, //viewport + 0x03,0x02,0x01,0xCC,0xCC,0xCC,0xCC,0xCC, 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC, //tests + //0x80: + 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC, 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC, + 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC, 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC, + 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC, 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC, + 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC, 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC, + 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC, 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC, + 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC, 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC, + 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC, 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC, + 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC, 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC +}; + + +//todo: it would be nice to make some kind of state machine that more closely models the hardware +//but this is servicable for now +class GXF_Hardware +{ +public: + GXF_Hardware() + { + reset(); + } + void test() { + printf("test 1: 0x00412321\n"); + receive(0x00412321); receive(1); receive(2); receive(3); receive(0); + //21: 1 + //23: 2 + //23: 3 + //41: 4 (a dud parameter) + printf("test 2: 0x00002321\n"); + receive(0x00002321); receive(1); receive(2); receive(3); + //21: 1 + //23: 2 + //23: 3 + printf("test 3: 0x11111111\n"); + receive(0x11111111); + receive(1); + //11: 1 (a dud parameter) + printf("test 4: 0x00000011, 0x29111111\n"); + receive(0x00000011); receive(0x29111111); receive(1); + //11: 17 + //11: 688984337 + //11: 1 + printf("test 5: 0x00004127\n"); + receive(0x00004127); receive(1); receive(0);//final one should be a dud + } + void reset() { + countdown = 0; + commandsPending = std::queue(); + countdowns = std::queue(); + } + //todo - things in here other than the very first thing involving GFX3D_NOP_NOARG_HACK I am not too sure about. + void receive(u32 val) { + bool hack = false; + if(commandsPending.size()>0 && (commandsPending.front() == 0x15 || commandsPending.front() == GFX3D_NOP_NOARG_HACK || commandsPending.front() == 0x11 || commandsPending.front() == 0x41) && val != 0) { + //apparently a zero is swallowed in this case but if another value is sent + //processing will continue + //if(commandsPending.front() == GFX3D_NOP_NOARG_HACK) + //{} + //else + { + //printf("gxf: sending hack %02X: (dummy=0)\n", commandsPending.front()); + GFX_FIFOsend(commandsPending.front(),0); + } + hack = true; + goto hackTrigger; + } + if(countdown>0) { + //received a parameter + //printf("gxf: sending %02X: %08X\n", commandsPending.front(),val); + //if(commandsPending.front() == GFX3D_NOP_NOARG_HACK) + //{} + //else + GFX_FIFOsend(commandsPending.front(),val); + hackTrigger: + countdown--; + while(countdown==0) { + commandsPending.pop(); + countdowns.pop(); + trigger: + //dont set hack to false if you jumped from below! it needs to be true for when you jump down from above. + //oh my what a mess. + if(countdowns.empty()) break; + countdown = countdowns.front(); + if(!countdown) { + if(commandsPending.front() != INVALID_COMMAND /*&& commandsPending.front() != GFX3D_NOP_NOARG_HACK*/) { + //printf("[%06d]gxf: sending %02X: (dummy=0)\n", currFrameCounter,commandsPending.front()); + GFX_FIFOsend(commandsPending.front(),0); + } + } + } + if(hack) goto decode; + } else { +decode: + //printf("[%05d] gxf: decoding %08X\n",currFrameCounter,val); + if(val==0x2D8B62D8) { + int zzz=9; + } + //received a packed command. unpack into commandsPending + bool valid = true; + bool gimpyCommand = false; + const u8 commands[] = { val&0xFF, (val>>8)&0xFF, (val>>16)&0xFF, (val>>24)&0xFF }; + const u8 commandTypes[] = { gfx3d_commandTypes[commands[0]], gfx3d_commandTypes[commands[1]],gfx3d_commandTypes[commands[2]], gfx3d_commandTypes[commands[3]] }; + + for(int i=0;i<4;i++) { + u8 cmd = commands[i]; + u8 type = commandTypes[i]; + if(type == INVALID_COMMAND) { + commandsPending.push(INVALID_COMMAND); + } else { + if(type == UNDEFINED_COMMAND) + commandsPending.push(GFX3D_NOP_NOARG_HACK); //enqueue a single undefined command we know how to handle + else commandsPending.push(cmd); + } + if(type == UNDEFINED_COMMAND || type == 0x00) { + //these are valid commands with no parameters. they might need special handling + //as long as there is a subsequent defined command with parameters, we're safe + bool safe = false; + for(int j=i+1;j<4;j++) { + if(commandTypes[j] != INVALID_COMMAND) { + safe = true; + break; + } + } + if(safe) { + countdowns.push(0); + } else { + //we need to receive a dummy parameter in this case + countdowns.push(1); + } + } else if(type != INVALID_COMMAND) { + countdowns.push(type); + } else countdowns.push(0); + } + + countdown = countdowns.front(); + if(countdown==0) + goto trigger; + } + } + std::queue commandsPending; + std::queue countdowns; + u8 countdown; + + void savestate(EMUFILE *f) + { + write32le(0,f); //version + std::queue temp = commandsPending; + write32le(temp.size(),f); + while(!temp.empty()) { write8le(temp.front(),f); temp.pop(); } + temp = countdowns; + write32le(temp.size(),f); + while(!temp.empty()) { write8le(temp.front(),f); temp.pop(); } + + write8le(countdown,f); + } + + bool loadstate(EMUFILE *f) + { + u32 version; + if(read32le(&version,f) != 1) return false; + if(version != 0) return false; + + assert(commandsPending.size()==0); + assert(countdowns.size()==0); + + u32 temp; + read32le(&temp,f); + for(u32 i=0;ilist[vertlist->count + tempVertInfo.count - continuation]; + int vertIndex = vertlist->count + tempVertInfo.count - continuation; + if(vertIndex<0) { + printf("wtf\n"); + } + VERT &vert = vertlist->list[vertIndex]; + + //printf("%f %f %f\n",coordTransformed[0],coordTransformed[1],coordTransformed[2]); + //if(coordTransformed[1] > 20) + // coordTransformed[1] = 20; + + //printf("y-> %f\n",coord[1]); + + //if(mtxCurrent[1][14]>15) { + // printf("ACK!\n"); + // printf("----> modelview 1 state for that ack:\n"); + // //MatrixPrint(mtxCurrent[1]); + //} vert.texcoord[0] = last_s; vert.texcoord[1] = last_t; @@ -559,18 +769,18 @@ void gfx3d_glMatrixMode(u32 v) void gfx3d_glPushMatrix() { - u32 gxstat = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x600); + //u32 gxstat = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x600); //this command always works on both pos and vector when either pos or pos-vector are the current mtx mode short mymode = (mode==1?2:mode); if (mtxStack[mymode].position > mtxStack[mymode].size) { - gxstat |= (1<<15); - T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x600, gxstat); + MMU_new.gxstat.se = 1; + //gxstat |= (1<<15); return; } - gxstat &= 0xFFFF00FF; + //gxstat &= 0xFFFF00FF; MatrixStackPushMatrix(&mtxStack[mymode], mtxCurrent[mymode]); @@ -579,26 +789,23 @@ void gfx3d_glPushMatrix() if(mymode==2) MatrixStackPushMatrix (&mtxStack[1], mtxCurrent[1]); - gxstat |= ((mtxStack[0].position << 13) | (mtxStack[1].position << 8)); - T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x600, gxstat); + //gxstat |= ((mtxStack[0].position << 13) | (mtxStack[1].position << 8)); } void gfx3d_glPopMatrix(s32 i) { - u32 gxstat = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x600); - //this command always works on both pos and vector when either pos or pos-vector are the current mtx mode short mymode = (mode==1?2:mode); - /* + if (i > mtxStack[mymode].position) { - gxstat |= (1<<15); - T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x600, gxstat); - return; + //was commented out before zero sep modifications + MMU_new.gxstat.se = 1; + // T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x600, gxstat); + // return; } - */ - gxstat &= 0xFFFF00FF; + MatrixCopy(mtxCurrent[mymode], MatrixStackPopMatrix (&mtxStack[mymode], i)); @@ -607,8 +814,7 @@ void gfx3d_glPopMatrix(s32 i) if (mymode == 2) MatrixCopy(mtxCurrent[1], MatrixStackPopMatrix (&mtxStack[1], i)); - gxstat |= ((mtxStack[0].position << 13) | (mtxStack[1].position << 8)); - T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x600, gxstat); + //gxstat |= ((mtxStack[0].position << 13) | (mtxStack[1].position << 8)); } void gfx3d_glStoreMatrix(u32 v) @@ -649,6 +855,9 @@ void gfx3d_glRestoreMatrix(u32 v) if (mymode == 2) MatrixCopy (mtxCurrent[1], MatrixStackGetPos(&mtxStack[1], v)); + + //printf("restore: matrix %d to: \n",mymode); MatrixPrint(mtxCurrent[1]); + } void gfx3d_glLoadIdentity() @@ -659,6 +868,8 @@ void gfx3d_glLoadIdentity() if (mode == 2) MatrixIdentity (mtxCurrent[1]); + + //printf("identity: %d to: \n",mode); MatrixPrint(mtxCurrent[1]); } BOOL gfx3d_glLoadMatrix4x4(s32 v) @@ -675,6 +886,8 @@ BOOL gfx3d_glLoadMatrix4x4(s32 v) if (mode == 2) MatrixCopy (mtxCurrent[1], mtxCurrent[2]); + + //printf("load4x4: matrix %d to: \n",mode); MatrixPrint(mtxCurrent[1]); return TRUE; } @@ -697,6 +910,7 @@ BOOL gfx3d_glLoadMatrix4x3(s32 v) if (mode == 2) MatrixCopy (mtxCurrent[1], mtxCurrent[2]); + //printf("load4x3: matrix %d to: \n",mode); MatrixPrint(mtxCurrent[1]); return TRUE; } @@ -720,6 +934,8 @@ BOOL gfx3d_glMultMatrix4x4(s32 v) GFX_DELAY_M2(30); } + //printf("mult4x4: matrix %d to: \n",mode); MatrixPrint(mtxCurrent[1]); + MatrixIdentity (mtxTemporal); return TRUE; } @@ -749,6 +965,8 @@ BOOL gfx3d_glMultMatrix4x3(s32 v) GFX_DELAY_M2(30); } + //printf("mult4x3: matrix %d to: \n",mode); MatrixPrint(mtxCurrent[1]); + //does this really need to be done? MatrixIdentity (mtxTemporal); return TRUE; @@ -781,6 +999,9 @@ BOOL gfx3d_glMultMatrix3x3(s32 v) GFX_DELAY_M2(30); } + //printf("mult3x3: matrix %d to: \n",mode); MatrixPrint(mtxCurrent[1]); + + //does this really need to be done? MatrixIdentity (mtxTemporal); return TRUE; @@ -796,6 +1017,7 @@ BOOL gfx3d_glScale(s32 v) scaleind = 0; MatrixScale (mtxCurrent[(mode==2?1:mode)], scale); + //printf("scale: matrix %d to: \n",mode); MatrixPrint(mtxCurrent[1]); GFX_DELAY(22); @@ -825,6 +1047,9 @@ BOOL gfx3d_glTranslate(s32 v) MatrixTranslate (mtxCurrent[1], trans); GFX_DELAY_M2(30); } + + //printf("translate: matrix %d to: \n",mode); MatrixPrint(mtxCurrent[1]); + return TRUE; } @@ -1122,10 +1347,8 @@ void gfx3d_glViewPort(u32 v) BOOL gfx3d_glBoxTest(u32 v) { - u32 gxstat = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x600); - gxstat &= 0xFFFFFFFD; // clear boxtest bit - gxstat |= 0x00000001; // busy - T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x600, gxstat); + //gxstat &= 0xFFFFFFFD; // clear boxtest bit + //gxstat |= 0x00000001; // busy BTcoords[BTind++] = float16table[v & 0xFFFF]; BTcoords[BTind++] = float16table[v >> 16]; @@ -1140,7 +1363,7 @@ BOOL gfx3d_glBoxTest(u32 v) if (BTind < 5) return FALSE; BTind = 0; - gxstat &= 0xFFFFFFFE; // clear busy bit + //gxstat &= 0xFFFFFFFE; // clear busy bit GFX_DELAY(103); #if 0 @@ -1217,18 +1440,15 @@ BOOL gfx3d_glBoxTest(u32 v) } #else - gxstat |= 0x00000002; // hack + //gxstat |= 0x00000002; // hack #endif - T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x600, gxstat); return TRUE; } BOOL gfx3d_glPosTest(u32 v) { - u32 gxstat = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x600); - gxstat |= 0x00000001; // busy - T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x600, gxstat); + //gxstat |= 0x00000001; // busy PTcoords[PTind++] = float16table[v & 0xFFFF]; PTcoords[PTind++] = float16table[v >> 16]; @@ -1241,8 +1461,7 @@ BOOL gfx3d_glPosTest(u32 v) MatrixMultVec4x4(mtxCurrent[1], PTcoords); MatrixMultVec4x4(mtxCurrent[0], PTcoords); - gxstat &= 0xFFFFFFFE; - T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x600, gxstat); + //gxstat &= 0xFFFFFFFE; GFX_DELAY(9); @@ -1251,9 +1470,7 @@ BOOL gfx3d_glPosTest(u32 v) void gfx3d_glVecTest(u32 v) { - u32 gxstat = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x600); - gxstat &= 0xFFFFFFFE; - T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x600, gxstat); + //gxstat &= 0xFFFFFFFE; GFX_DELAY(5); //INFO("NDS_glVecTest\n"); @@ -1338,6 +1555,8 @@ s32 gfx3d_GetDirectionalMatrix (unsigned int index) void gfx3d_ClearStack() { MatrixStackSetStackPosition(&mtxStack[0], -5); + //MatrixStackSetStackPosition(&mtxStack[1], -55); + //MatrixStackSetStackPosition(&mtxStack[2], -55); //? MatrixStackSetStackPosition(&mtxStack[3], -5); } @@ -1357,10 +1576,8 @@ unsigned short gfx3d_glGetVecRes(unsigned int index) return 0; } -#ifdef USE_GEOMETRY_FIFO_EMULATION - //#define _3D_LOG_EXEC -void FORCEINLINE gfx3d_execute(u8 cmd, u32 param) +void gfx3d_execute(u8 cmd, u32 param) { #ifdef _3D_LOG_EXEC u32 gxstat2 = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x600); @@ -1483,7 +1700,6 @@ void FORCEINLINE gfx3d_execute(u8 cmd, u32 param) INFO("Unknown execute FIFO 3D command 0x%02X with param 0x%08X\n", cmd, param); break; } - NDS_RescheduleGXFIFO(); } void gfx3d_execute3D() @@ -1491,19 +1707,45 @@ void gfx3d_execute3D() u8 cmd = 0; u32 param = 0; +#ifndef FLUSHMODE_HACK if (isSwapBuffers) return; +#endif - if (GFX_PIPErecv(&cmd, ¶m)) + if(GFX_PIPErecv(&cmd, ¶m)) { + //since we did anything at all, incur a pipeline motion cost. + //also, we can't let gxfifo sequencer stall until the fifo is empty. + //see... + GFX_DELAY(1); + + //..these guys will ordinarily set a delay, but multi-param operations won't + //for the earlier params. + //printf("%05d:%03d:%12lld: executed 3d: %02X %08X\n",currFrameCounter, nds.VCount, nds_timer , cmd, param); gfx3d_execute(cmd, param); } + + + //i thought it might be right to move these here, but it didnt help. + //maybe its a good idea for later. + + //if(gxFIFO.size <= 127) + //{ + // if(gxstat.gxfifo_irq == 1) + // setIF(0, (1<<21)); //the half gxfifo irq + // + // //might need to trigger a gxfifo dma + // triggerDma(EDMAMode_GXFifo); + //} + + //if(gxFIFO.size == 0) { + // if(gxstat.gxfifo_irq == 2) + // setIF(0, (1<<21)); //the empty gxfifo irq + //} } -#endif + void gfx3d_glFlush(u32 v) { - -#ifdef USE_GEOMETRY_FIFO_EMULATION gfx3d.sortmode = BIT0(v); gfx3d.wbuffer = BIT1(v); #if 0 @@ -1512,19 +1754,16 @@ void gfx3d_glFlush(u32 v) INFO("Error: swapBuffers already use\n"); } #endif - isSwapBuffers = true; -#else - if(!flushPending) - { - gfx3d.sortmode = BIT0(v); - gfx3d.wbuffer = BIT1(v); - flushPending = TRUE; - } - //see discussion at top of file - if(CommonSettings.gfx3d_flushMode == 0) - gfx3d_doFlush(); -#endif + isSwapBuffers = TRUE; + + //well, the game wanted us to flush. + //it may be badly timed. lets just flush it. +#ifdef FLUSHMODE_HACK + gfx3d_doFlush(); +#endif + + GFX_DELAY(1); } static bool gfx3d_ysort_compare(int num1, int num2) @@ -1554,14 +1793,6 @@ static void gfx3d_doFlush() { gfx3d.frameCtr++; -#ifndef USE_GEOMETRY_FIFO_EMULATION - GFX_PIPEclear(); - GFX_FIFOclear(); - // reset - clInd = 0; - clCmd = 0; -#endif - //the renderer will get the lists we just built gfx3d.polylist = polylist; gfx3d.vertlist = vertlist; @@ -1635,50 +1866,29 @@ static void gfx3d_doFlush() //switch to the new lists twiddleLists(); -#ifndef USE_GEOMETRY_FIFO_EMULATION - flushPending = FALSE; drawPending = TRUE; -#else - drawPending = TRUE; -#endif } void gfx3d_VBlankSignal() { -#ifdef USE_GEOMETRY_FIFO_EMULATION isVBlank = true; if (isSwapBuffers) { - gfx3d_doFlush(); - isSwapBuffers = false; - } -#else - //the 3d buffers are swapped when a vblank begins. - //so, if we have a redraw pending, now is a safe time to do it - if(!flushPending) - { - GFX_PIPEclear(); - GFX_FIFOclear(); - return; - } - - //see discussion at top of file - if(CommonSettings.gfx3d_flushMode == 1) +#ifndef FLUSHMODE_HACK gfx3d_doFlush(); #endif + GFX_DELAY(392); + isSwapBuffers = FALSE; + } } void gfx3d_VBlankEndSignal(bool skipFrame) { -#ifdef USE_GEOMETRY_FIFO_EMULATION isVBlank = false; if (!drawPending) return; drawPending = FALSE; - GFX_DELAY(392); - NDS_RescheduleGXFIFO(); - if(skipFrame) return; //if the null 3d core is chosen, then we need to clear out the 3d buffers to keep old data from being rendered if(gpu3D == &gpu3DNull || !CommonSettings.showGpu.main) @@ -1688,186 +1898,13 @@ void gfx3d_VBlankEndSignal(bool skipFrame) } gpu3D->NDS_3D_Render(); -#else - //if we are skipping 3d frames then the 3d rendering will get held up here. - //but, as soon as we quit skipping frames, the held-up 3d frame will render - if(skipFrame) return; - if(!drawPending) return; - - drawPending = FALSE; - - if(CommonSettings.showGpu.main) - gpu3D->NDS_3D_Render(); - - //if the null 3d core is chosen, then we need to clear out the 3d buffers to keep old data from being rendered - if(gpu3D == &gpu3DNull || !CommonSettings.showGpu.main) - { - memset(gfx3d_convertedScreen,0,sizeof(gfx3d_convertedScreen)); - } -#endif } -#ifdef USE_GEOMETRY_FIFO_EMULATION //#define _3D_LOG -// http://nocash.emubase.de/gbatek.htm#ds3dvideo -// DS 3D Geometry Commands -// Sending Commands by Ports 4000440h..40005FFh -// -// If the FIFO is full, then a wait is generated until data is removed from the FIFO, -// ie. the STR opcode gets freezed, during the wait, the bus cannot be used even by DMA, -// interrupts, or by the NDS7 CPU. - -// this is a hack -#if 1 -#define CHECKFULL() if (gxFIFO.size > 255) \ - {\ - gfx3d_execute3D();\ - gfx3d_execute3D();\ - gfx3d_execute3D();\ - gfx3d_execute3D();\ - } -#else -#define CHECKFULL() ; -#endif - -static void NOPARAMS() -{ - for (;;) - { - if (clCmd == 0) return; - switch (clCmd & 0xFF) - { - case 0x00: - { - clCmd >>= 8; - continue; - } - case 0x11: - case 0x15: - case 0x41: - { - CHECKFULL(); - GFX_FIFOsend(clCmd & 0xFF, 0); - clCmd >>= 8; - continue; - } - } - break; - } -} - void gfx3d_sendCommandToFIFO(u32 val) { - if (clCmd == 0) - { - clInd2 = 0; - clCmd = val; - NOPARAMS(); - return; - } -#ifdef _3D_LOG - INFO("gxFIFO: send 0x%02X: val=0x%08X, pipe %02i, fifo %03i\n", clCmd & 0xFF, val, gxPIPE.tail, gxFIFO.tail); -#endif - - CHECKFULL(); - - switch (clCmd & 0xFF) - { - case 0x34: // SHININESS - Specular Reflection Shininess Table (W) - GFX_FIFOsend(clCmd & 0xFF, val); - - clInd2++; - if (clInd2 < 32) return; - clInd2 = 0; - clCmd >>= 8; - break; - - case 0x16: // MTX_LOAD_4x4 - Load 4x4 Matrix to Current Matrix (W) - case 0x18: // MTX_MULT_4x4 - Multiply Current Matrix by 4x4 Matrix (W) - GFX_FIFOsend(clCmd & 0xFF, val); - - clInd2++; - if (clInd2 < 16) return; - clInd2 = 0; - clCmd >>= 8; - break; - - case 0x17: // MTX_LOAD_4x3 - Load 4x3 Matrix to Current Matrix (W) - case 0x19: // MTX_MULT_4x3 - Multiply Current Matrix by 4x3 Matrix (W) - GFX_FIFOsend(clCmd & 0xFF, val); - - clInd2++; - if (clInd2 < 12) return; - clInd2 = 0; - clCmd >>= 8; - break; - - case 0x1A: // MTX_MULT_3x3 - Multiply Current Matrix by 3x3 Matrix (W) - GFX_FIFOsend(clCmd & 0xFF, val); - - clInd2++; - if (clInd2 < 9) return; - clInd2 = 0; - clCmd >>= 8; - break; - - case 0x1B: // MTX_SCALE - Multiply Current Matrix by Scale Matrix (W) - case 0x1C: // MTX_TRANS - Mult. Curr. Matrix by Translation Matrix (W) - case 0x70: // BOX_TEST - Test if Cuboid Sits inside View Volume (W) - GFX_FIFOsend(clCmd & 0xFF, val); - - clInd2++; - if (clInd2 < 3) return; - clInd2 = 0; - clCmd >>= 8; - break; - - case 0x23: // VTX_16 - Set Vertex XYZ Coordinates (W) - case 0x71: // POS_TEST - Set Position Coordinates for Test (W) - GFX_FIFOsend(clCmd & 0xFF, val); - - clInd2++; - if (clInd2 < 2) return; - clInd2 = 0; - clCmd >>= 8; - break; - - case 0x10: // MTX_MODE - Set Matrix Mode (W) - case 0x12: // MTX_POP - Pop Current Matrix from Stack (W) - case 0x13: // MTX_STORE - Store Current Matrix on Stack (W) - case 0x14: // MTX_RESTORE - Restore Current Matrix from Stack (W) - case 0x20: // COLOR - Directly Set Vertex Color (W) - case 0x21: // NORMAL - Set Normal Vector (W) - case 0x22: // TEXCOORD - Set Texture Coordinates (W) - case 0x24: // VTX_10 - Set Vertex XYZ Coordinates (W) - case 0x25: // VTX_XY - Set Vertex XY Coordinates (W) - case 0x26: // VTX_XZ - Set Vertex XZ Coordinates (W) - case 0x27: // VTX_YZ - Set Vertex YZ Coordinates (W) - case 0x28: // VTX_DIFF - Set Relative Vertex Coordinates (W) - case 0x29: // POLYGON_ATTR - Set Polygon Attributes (W) - case 0x2A: // TEXIMAGE_PARAM - Set Texture Parameters (W) - case 0x2B: // PLTT_BASE - Set Texture Palette Base Address (W) - case 0x30: // DIF_AMB - MaterialColor0 - Diffuse/Ambient Reflect. (W) - case 0x31: // SPE_EMI - MaterialColor1 - Specular Ref. & Emission (W) - case 0x32: // LIGHT_VECTOR - Set Light's Directional Vector (W) - case 0x33: // LIGHT_COLOR - Set Light Color (W) - case 0x40: // BEGIN_VTXS - Start of Vertex List (W) - case 0x60: // VIEWPORT - Set Viewport (W) - case 0x72: // VEC_TEST - Set Directional Vector for Test (W) - GFX_FIFOsend(clCmd & 0xFF, val); - clCmd >>= 8; - break; - case 0x50: // SWAP_BUFFERS - Swap Rendering Engine Buffer (W) - GFX_FIFOsend(clCmd & 0xFF, val); - clCmd >>= 8; - break; - default: - INFO("Unknown FIFO 3D command 0x%02X (0x%08X)\n", clCmd&0xFF, clCmd); - clCmd >>= 8; - break; - } - NOPARAMS(); + gxf_hardware.receive(val); } void gfx3d_sendCommand(u32 cmd, u32 param) @@ -1877,8 +1914,6 @@ void gfx3d_sendCommand(u32 cmd, u32 param) INFO("gxFIFO: send 0x%02X: val=0x%08X, pipe %02i, fifo %03i (direct)\n", cmd, param, gxPIPE.tail, gxFIFO.tail); #endif - CHECKFULL(); - switch (cmd) { case 0x10: // MTX_MODE - Set Matrix Mode (W) @@ -1917,9 +1952,11 @@ void gfx3d_sendCommand(u32 cmd, u32 param) case 0x70: // BOX_TEST - Test if Cuboid Sits inside View Volume (W) case 0x71: // POS_TEST - Set Position Coordinates for Test (W) case 0x72: // VEC_TEST - Set Directional Vector for Test (W) + //printf("mmu: sending %02X: %08X\n", cmd,param); GFX_FIFOsend(cmd, param); break; case 0x50: // SWAP_BUFFERS - Swap Rendering Engine Buffer (W) + //printf("mmu: sending %02X: %08X\n", cmd,param); GFX_FIFOsend(cmd, param); break; default: @@ -1928,382 +1965,7 @@ void gfx3d_sendCommand(u32 cmd, u32 param) } } -#else -//#define _3D_LOG -static void NOPARAMS() -{ - for (;;) - { - if (clCmd == 0) return; - switch (clCmd & 0xFF) - { - case 0x00: - { - clCmd >>= 8; - continue; - } - case 0x11: - { - gfx3d_glPushMatrix(); - GFX_FIFOsend(clCmd & 0xFF, 0); - clCmd >>= 8; - continue; - } - case 0x15: - { - gfx3d_glLoadIdentity(); - GFX_FIFOsend(clCmd & 0xFF, 0); - clCmd >>= 8; - continue; - } - case 0x41: - { - gfx3d_glEnd(); - GFX_FIFOsend(clCmd & 0xFF, 0); - clCmd >>= 8; - continue; - } - } - break; - } -} - -void gfx3d_sendCommandToFIFO(u32 val) -{ - //friendly reminder: be careful to handle the case where several unpacked noparams commands get sent in a row! - - if (clCmd == 0) - { - clCmd = val; - NOPARAMS(); - return; - } -#ifdef _3D_LOG - INFO("GFX FIFO: Send GFX 3D cmd 0x%02X to FIFO (0x%08X)\n", clCmd & 0xFF, val); -#endif - - switch (clCmd & 0xFF) - { - case 0x10: // MTX_MODE - Set Matrix Mode (W) - GFX_FIFOsend(clCmd & 0xFF, val); - gfx3d_glMatrixMode(val); - clCmd >>= 8; - break; - case 0x12: // MTX_POP - Pop Current Matrix from Stack (W) - GFX_FIFOsend(clCmd & 0xFF, val); - gfx3d_glPopMatrix(val); - clCmd >>= 8; - break; - case 0x13: // MTX_STORE - Store Current Matrix on Stack (W) - GFX_FIFOsend(clCmd & 0xFF, val); - gfx3d_glStoreMatrix(val); - clCmd >>= 8; - break; - case 0x14: // MTX_RESTORE - Restore Current Matrix from Stack (W) - GFX_FIFOsend(clCmd & 0xFF, val); - gfx3d_glRestoreMatrix(val); - clCmd >>= 8; - break; - case 0x16: // MTX_LOAD_4x4 - Load 4x4 Matrix to Current Matrix (W) - GFX_FIFOsend(clCmd & 0xFF, val); - if (!gfx3d_glLoadMatrix4x4(val)) break; - clCmd >>= 8; - break; - case 0x17: // MTX_LOAD_4x3 - Load 4x3 Matrix to Current Matrix (W) - GFX_FIFOsend(clCmd & 0xFF, val); - if (!gfx3d_glLoadMatrix4x3(val)) break; - clCmd >>= 8; - break; - case 0x18: // MTX_MULT_4x4 - Multiply Current Matrix by 4x4 Matrix (W) - GFX_FIFOsend(clCmd & 0xFF, val); - if (!gfx3d_glMultMatrix4x4(val)) break; - clCmd >>= 8; - break; - case 0x19: // MTX_MULT_4x3 - Multiply Current Matrix by 4x3 Matrix (W) - GFX_FIFOsend(clCmd & 0xFF, val); - if (!gfx3d_glMultMatrix4x3(val)) break; - clCmd >>= 8; - break; - case 0x1A: // MTX_MULT_3x3 - Multiply Current Matrix by 3x3 Matrix (W) - GFX_FIFOsend(clCmd & 0xFF, val); - if (!gfx3d_glMultMatrix3x3(val)) break; - clCmd >>= 8; - break; - case 0x1B: // MTX_SCALE - Multiply Current Matrix by Scale Matrix (W) - GFX_FIFOsend(clCmd & 0xFF, val); - if (!gfx3d_glScale(val)) break; - clCmd >>= 8; - break; - case 0x1C: // MTX_TRANS - Mult. Curr. Matrix by Translation Matrix (W) - GFX_FIFOsend(clCmd & 0xFF, val); - if (!gfx3d_glTranslate(val)) break; - clCmd >>= 8; - break; - case 0x20: // COLOR - Directly Set Vertex Color (W) - GFX_FIFOsend(clCmd & 0xFF, val); - gfx3d_glColor3b(val); - clCmd >>= 8; - break; - case 0x21: // NORMAL - Set Normal Vector (W) - GFX_FIFOsend(clCmd & 0xFF, val); - gfx3d_glNormal(val); - clCmd >>= 8; - break; - case 0x22: // TEXCOORD - Set Texture Coordinates (W) - GFX_FIFOsend(clCmd & 0xFF, val); - gfx3d_glTexCoord(val); - clCmd >>= 8; - break; - case 0x23: // VTX_16 - Set Vertex XYZ Coordinates (W) - GFX_FIFOsend(clCmd & 0xFF, val); - if (!gfx3d_glVertex16b(val)) break; - clCmd >>= 8; - break; - case 0x24: // VTX_10 - Set Vertex XYZ Coordinates (W) - GFX_FIFOsend(clCmd & 0xFF, val); - gfx3d_glVertex10b(val); - clCmd >>= 8; - break; - case 0x25: // VTX_XY - Set Vertex XY Coordinates (W) - GFX_FIFOsend(clCmd & 0xFF, val); - gfx3d_glVertex3_cord(0, 1, val); - clCmd >>= 8; - break; - case 0x26: // VTX_XZ - Set Vertex XZ Coordinates (W) - GFX_FIFOsend(clCmd & 0xFF, val); - gfx3d_glVertex3_cord(0, 2, val); - clCmd >>= 8; - break; - case 0x27: // VTX_YZ - Set Vertex YZ Coordinates (W) - GFX_FIFOsend(clCmd & 0xFF, val); - gfx3d_glVertex3_cord(1, 2, val); - clCmd >>= 8; - break; - case 0x28: // VTX_DIFF - Set Relative Vertex Coordinates (W) - GFX_FIFOsend(clCmd & 0xFF, val); - gfx3d_glVertex_rel(val); - clCmd >>= 8; - break; - case 0x29: // POLYGON_ATTR - Set Polygon Attributes (W) - GFX_FIFOsend(clCmd & 0xFF, val); - gfx3d_glPolygonAttrib(val); - clCmd >>= 8; - break; - case 0x2A: // TEXIMAGE_PARAM - Set Texture Parameters (W) - GFX_FIFOsend(clCmd & 0xFF, val); - gfx3d_glTexImage(val); - clCmd >>= 8; - break; - case 0x2B: // PLTT_BASE - Set Texture Palette Base Address (W) - GFX_FIFOsend(clCmd & 0xFF, val); - gfx3d_glTexPalette(val); - clCmd >>= 8; - break; - case 0x30: // DIF_AMB - MaterialColor0 - Diffuse/Ambient Reflect. (W) - GFX_FIFOsend(clCmd & 0xFF, val); - gfx3d_glMaterial0(val); - clCmd >>= 8; - break; - case 0x31: // SPE_EMI - MaterialColor1 - Specular Ref. & Emission (W) - GFX_FIFOsend(clCmd & 0xFF, val); - gfx3d_glMaterial1(val); - clCmd >>= 8; - break; - case 0x32: // LIGHT_VECTOR - Set Light's Directional Vector (W) - GFX_FIFOsend(clCmd & 0xFF, val); - gfx3d_glLightDirection(val); - clCmd >>= 8; - break; - case 0x33: // LIGHT_COLOR - Set Light Color (W) - GFX_FIFOsend(clCmd & 0xFF, val); - gfx3d_glLightColor(val); - clCmd >>= 8; - break; - case 0x34: // SHININESS - Specular Reflection Shininess Table (W) - GFX_FIFOsend(clCmd & 0xFF, val); - if (!gfx3d_glShininess(val)) break; - clCmd >>= 8; - break; - case 0x40: // BEGIN_VTXS - Start of Vertex List (W) - GFX_FIFOsend(clCmd & 0xFF, val); - gfx3d_glBegin(val); - clCmd >>= 8; - break; - case 0x50: // SWAP_BUFFERS - Swap Rendering Engine Buffer (W) - gfx3d_glFlush(val); - break; - case 0x60: // VIEWPORT - Set Viewport (W) - GFX_FIFOsend(clCmd & 0xFF, val); - gfx3d_glViewPort(val); - clCmd >>= 8; - break; - case 0x70: // BOX_TEST - Test if Cuboid Sits inside View Volume (W) - GFX_FIFOsend(clCmd & 0xFF, val); - if (!gfx3d_glBoxTest(val)) break; - clCmd >>= 8; - break; - case 0x71: // POS_TEST - Set Position Coordinates for Test (W) - GFX_FIFOsend(clCmd & 0xFF, val); - if (!gfx3d_glPosTest(val)) break; - clCmd >>= 8; - break; - case 0x72: // VEC_TEST - Set Directional Vector for Test (W) - GFX_FIFOsend(clCmd & 0xFF, val); - gfx3d_glVecTest(val); - clCmd >>= 8; - break; - default: - LOG("Unknown FIFO 3D command 0x%02X in cmd=0x%02X\n", clCmd&0xFF, val); - clCmd >>= 8; - break; - } - NOPARAMS(); -} - -void gfx3d_sendCommand(u32 cmd, u32 param) -{ - cmd &= 0x0FFF; -#ifdef _3D_LOG - INFO("GFX FIFO: Send GFX 3D cmd 0x%02X to FIFO (0x%08X) - DIRECT\n", (cmd & 0x1FF)>>2, param); -#endif - - switch (cmd) - { - case 0x340: // Alpha test reference value - Parameters:1 - gfx3d_glAlphaFunc(param); - break; - case 0x350: // Clear background color setup - Parameters:2 - gfx3d_glClearColor(param); - break; - case 0x354: // Clear background depth setup - Parameters:2 - gfx3d_glClearDepth(param); - break; - case 0x356: // Rear-plane Bitmap Scroll Offsets (W) - break; - case 0x358: // Fog Color - Parameters:4b - gfx3d_glFogColor(param); - break; - case 0x35C: - gfx3d_glFogOffset(param); - break; - case 0x440: // MTX_MODE - Set Matrix Mode (W) - gfx3d_glMatrixMode(param); - break; - case 0x444: // MTX_PUSH - Push Current Matrix on Stack (W) - gfx3d_glPushMatrix(); - break; - case 0x448: // MTX_POP - Pop Current Matrix from Stack (W) - gfx3d_glPopMatrix(param); - break; - case 0x44C: // MTX_STORE - Store Current Matrix on Stack (W) - gfx3d_glStoreMatrix(param); - break; - case 0x450: // MTX_RESTORE - Restore Current Matrix from Stack (W) - gfx3d_glRestoreMatrix(param); - break; - case 0x454: // MTX_IDENTITY - Load Unit Matrix to Current Matrix (W) - gfx3d_glLoadIdentity(); - break; - case 0x458: // MTX_LOAD_4x4 - Load 4x4 Matrix to Current Matrix (W) - gfx3d_glLoadMatrix4x4(param); - break; - case 0x45C: // MTX_LOAD_4x3 - Load 4x3 Matrix to Current Matrix (W) - gfx3d_glLoadMatrix4x3(param); - break; - case 0x460: // MTX_MULT_4x4 - Multiply Current Matrix by 4x4 Matrix (W) - gfx3d_glMultMatrix4x4(param); - break; - case 0x464: // MTX_MULT_4x3 - Multiply Current Matrix by 4x3 Matrix (W) - gfx3d_glMultMatrix4x3(param); - break; - case 0x468: // MTX_MULT_3x3 - Multiply Current Matrix by 3x3 Matrix (W) - gfx3d_glMultMatrix3x3(param); - break; - case 0x46C: // MTX_SCALE - Multiply Current Matrix by Scale Matrix (W) - gfx3d_glScale(param); - break; - case 0x470: // MTX_TRANS - Mult. Curr. Matrix by Translation Matrix (W) - gfx3d_glTranslate(param); - break; - case 0x480: // COLOR - Directly Set Vertex Color (W) - gfx3d_glColor3b(param); - break; - case 0x484: // NORMAL - Set Normal Vector (W) - gfx3d_glNormal(param); - break; - case 0x488: // TEXCOORD - Set Texture Coordinates (W) - gfx3d_glTexCoord(param); - break; - case 0x48C: // VTX_16 - Set Vertex XYZ Coordinates (W) - gfx3d_glVertex16b(param); - break; - case 0x490: // VTX_10 - Set Vertex XYZ Coordinates (W) - gfx3d_glVertex10b(param); - break; - case 0x494: // VTX_XY - Set Vertex XY Coordinates (W) - gfx3d_glVertex3_cord(0, 1, param); - break; - case 0x498: // VTX_XZ - Set Vertex XZ Coordinates (W) - gfx3d_glVertex3_cord(0, 2, param); - break; - case 0x49C: // VTX_YZ - Set Vertex YZ Coordinates (W) - gfx3d_glVertex3_cord(1, 2, param); - break; - case 0x4A0: // VTX_DIFF - Set Relative Vertex Coordinates (W) - gfx3d_glVertex_rel(param); - break; - case 0x4A4: // POLYGON_ATTR - Set Polygon Attributes (W) - gfx3d_glPolygonAttrib(param); - break; - case 0x4A8: // TEXIMAGE_PARAM - Set Texture Parameters (W) - gfx3d_glTexImage(param); - break; - case 0x4AC: // PLTT_BASE - Set Texture Palette Base Address (W) - gfx3d_glTexPalette(param); - break; - case 0x4C0: // DIF_AMB - MaterialColor0 - Diffuse/Ambient Reflect. (W) - gfx3d_glMaterial0(param); - break; - case 0x4C4: // SPE_EMI - MaterialColor1 - Specular Ref. & Emission (W) - gfx3d_glMaterial1(param); - break; - case 0x4C8: // LIGHT_VECTOR - Set Light's Directional Vector (W) - gfx3d_glLightDirection(param); - break; - case 0x4CC: // LIGHT_COLOR - Set Light Color (W) - gfx3d_glLightColor(param); - break; - case 0x4D0: // SHININESS - Specular Reflection Shininess Table (W) - gfx3d_glShininess(param); - break; - case 0x500: // BEGIN_VTXS - Start of Vertex List (W) - gfx3d_glBegin(param); - break; - case 0x504: // END_VTXS - End of Vertex List (W) - gfx3d_glEnd(); - break; - case 0x540: // SWAP_BUFFERS - Swap Rendering Engine Buffer (W) - gfx3d_glFlush(param); - break; - case 0x580: // VIEWPORT - Set Viewport (W) - gfx3d_glViewPort(param); - break; - case 0x5C0: // BOX_TEST - Test if Cuboid Sits inside View Volume (W) - gfx3d_glBoxTest(param); - break; - case 0x5C4: // POS_TEST - Set Position Coordinates for Test (W) - gfx3d_glPosTest(param); - break; - case 0x5C8: // VEC_TEST - Set Directional Vector for Test (W) - gfx3d_glVecTest(param); - break; - default: - LOG("Execute direct Port 3D command %03X in param=0x%08X\n", cmd, param); - break; - } -} -#endif void gfx3d_Control(u32 v) { @@ -2389,18 +2051,16 @@ SFORMAT SF_GFX3D[]={ { "GL_S", 4, 1, &last_s}, { "GLCM", 4, 1, &clCmd}, { "GLIN", 4, 1, &clInd}, -#ifdef USE_GEOMETRY_FIFO_EMULATION { "GLI2", 4, 1, &clInd2}, - { "GLSB", 1, 1, &isSwapBuffers}, -#endif + { "GLSB", 4, 1, &isSwapBuffers}, { "GLBT", 4, 1, &BTind}, { "GLPT", 4, 1, &PTind}, { "GLPC", 4, 4, PTcoords}, - { "GFHE", 2, 1, &gxFIFO.head}, - { "GFTA", 2, 1, &gxFIFO.tail}, - { "GFSZ", 2, 1, &gxFIFO.size}, - { "GFCM", 1, 256, &gxFIFO.cmd[0]}, - { "GFPM", 4, 256, &gxFIFO.param[0]}, + { "GFHE", 4, 1, &gxFIFO.head}, + { "GFTA", 4, 1, &gxFIFO.tail}, + { "GFSZ", 4, 1, &gxFIFO.size}, + { "GFCM", 1, HACK_GXIFO_SIZE, &gxFIFO.cmd[0]}, + { "GFPM", 4, HACK_GXIFO_SIZE, &gxFIFO.param[0]}, { "GPHE", 1, 1, &gxPIPE.head}, { "GPTA", 1, 1, &gxPIPE.tail}, { "GPSZ", 1, 1, &gxPIPE.size}, @@ -2449,7 +2109,7 @@ SFORMAT SF_GFX3D[]={ void gfx3d_savestate(EMUFILE* os) { //version - write32le(2,os); + write32le(3,os); //dump the render lists OSWRITE(vertlist->count); @@ -2465,6 +2125,8 @@ void gfx3d_savestate(EMUFILE* os) for(int j=0;j=3) { + gxf_hardware.loadstate(is); + } + gfx3d.polylist = &polylists[listTwiddle^1]; gfx3d.vertlist = &vertlists[listTwiddle^1]; gfx3d.polylist->count=0; diff --git a/desmume/src/gfx3d.h b/desmume/src/gfx3d.h index 953c29b27..4264d0872 100644 --- a/desmume/src/gfx3d.h +++ b/desmume/src/gfx3d.h @@ -31,6 +31,47 @@ #include "emufile.h" +//geometry engine command numbers +#define GFX3D_NOP 0x00 +#define GFX3D_MTX_MODE 0x10 +#define GFX3D_MTX_PUSH 0x11 +#define GFX3D_MTX_POP 0x12 +#define GFX3D_MTX_STORE 0x13 +#define GFX3D_MTX_RESTORE 0x14 +#define GFX3D_MTX_IDENTITY 0x15 +#define GFX3D_MTX_LOAD_4x4 0x16 +#define GFX3D_MTX_LOAD_4x3 0x17 +#define GFX3D_MTX_MULT_4x4 0x18 +#define GFX3D_MTX_MULT_4x3 0x19 +#define GFX3D_MTX_MULT_3x3 0x1A +#define GFX3D_MTX_SCALE 0x1B +#define GFX3D_MTX_TRANS 0x1C +#define GFX3D_COLOR 0x20 +#define GFX3D_NORMAL 0x21 +#define GFX3D_TEXCOORD 0x22 +#define GFX3D_VTX_16 0x23 +#define GFX3D_VTX_10 0x24 +#define GFX3D_XY 0x25 +#define GFX3D_XZ 0x26 +#define GFX3D_YZ 0x27 +#define GFX3D_DIFF 0x28 +#define GFX3D_POLYGON_ATTR 0x29 +#define GFX3D_TEXIMAGE_PARAM 0x2A +#define GFX3D_PLTT_BASE 0x2B +#define GFX3D_DIF_AMB 0x30 +#define GFX3D_SPE_EMI 0x31 +#define GFX3D_LIGHT_VECTOR 0x32 +#define GFX3D_LIGHT_COLOR 0x33 +#define GFX3D_SHININESS 0x34 +#define GFX3D_BEGIN_VTXS 0x40 +#define GFX3D_END_VTXS 0x41 +#define GFX3D_SWAP_BUFFERS 0x50 +#define GFX3D_VIEWPORT 0x60 +#define GFX3D_BOX_TEST 0x70 +#define GFX3D_POS_TEST 0x71 +#define GFX3D_VEC_TEST 0x72 +#define GFX3D_NOP_NOARG_HACK 0xDD + //produce a 32bpp color from a DS RGB16 #define RGB16TO32(col,alpha) (((alpha)<<24) | ((((col) & 0x7C00)>>7)<<16) | ((((col) & 0x3E0)>>2)<<8) | (((col) & 0x1F)<<3)) @@ -274,44 +315,8 @@ extern CACHE_ALIGN const u8 material_3bit_to_8bit[8]; extern CACHE_ALIGN u8 gfx3d_convertedScreen[256*192*4]; extern CACHE_ALIGN u8 gfx3d_convertedAlpha[256*192*2]; //see cpp for explanation of illogical *2 -//GE commands: -#ifndef USE_GEOMETRY_FIFO_EMULATION -void gfx3d_glMatrixMode(u32 v); -void gfx3d_glPushMatrix(void); -void gfx3d_glPopMatrix(s32 i); -void gfx3d_glStoreMatrix(u32 v); -void gfx3d_glRestoreMatrix(u32 v); -void gfx3d_glLoadIdentity(); -BOOL gfx3d_glLoadMatrix4x4(s32 v); -BOOL gfx3d_glLoadMatrix4x3(s32 v); -BOOL gfx3d_glMultMatrix4x4(s32 v); -BOOL gfx3d_glMultMatrix3x3(s32 v); -BOOL gfx3d_glMultMatrix4x3(s32 v); -BOOL gfx3d_glScale(s32 v); -BOOL gfx3d_glTranslate(s32 v); -void gfx3d_glColor3b(u32 v); -void gfx3d_glNormal(u32 v); -void gfx3d_glTexCoord(u32 val); -BOOL gfx3d_glVertex16b(u32 v); -void gfx3d_glVertex10b(u32 v); -void gfx3d_glVertex3_cord(u32 one, u32 two, u32 v); -void gfx3d_glVertex_rel(u32 v); -void gfx3d_glPolygonAttrib (u32 val); -void gfx3d_glTexImage(u32 val); -void gfx3d_glTexPalette(u32 val); -void gfx3d_glMaterial0(u32 val); -void gfx3d_glMaterial1(u32 val); -void gfx3d_glLightDirection (u32 v); -void gfx3d_glLightColor (u32 v); -BOOL gfx3d_glShininess (u32 val); -void gfx3d_glBegin(u32 v); -void gfx3d_glEnd(void); -// SwapBuffers see follow -void gfx3d_glViewPort(u32 v); -BOOL gfx3d_glBoxTest(u32 v); -BOOL gfx3d_glPosTest(u32 v); -void gfx3d_glVecTest(u32 v); -#endif +extern BOOL isSwapBuffers; + void gfx3d_glFlush(u32 v); // end GE commands @@ -332,9 +337,7 @@ u16 gfx3d_glGetVecRes(u32 index); void gfx3d_VBlankSignal(); void gfx3d_VBlankEndSignal(bool skipFrame); void gfx3d_Control(u32 v); -#ifdef USE_GEOMETRY_FIFO_EMULATION void gfx3d_execute3D(); -#endif void gfx3d_sendCommandToFIFO(u32 val); void gfx3d_sendCommand(u32 cmd, u32 param); @@ -352,4 +355,5 @@ void gfx3d_savestate(EMUFILE* os); bool gfx3d_loadstate(EMUFILE* is, int size); void gfx3d_ClearStack(); -#endif + +#endif //_GFX3D_H_ diff --git a/desmume/src/rasterize.cpp b/desmume/src/rasterize.cpp index 7154f9551..5378d01ef 100644 --- a/desmume/src/rasterize.cpp +++ b/desmume/src/rasterize.cpp @@ -1353,6 +1353,7 @@ static void SoftRastRender() } //printf("%d %d %d %d\n",gfx3d.viewport.x,gfx3d.viewport.y,gfx3d.viewport.width,gfx3d.viewport.height); +// printf("%f\n",vert.coord[0]); //viewport transforms for(int i=0;i +int readle(T *Bufo, EMUFILE*is) +{ + CTASSERT(sizeof(T)==1||sizeof(T)==2||sizeof(T)==4||sizeof(T)==8); + switch(sizeof(T)) { + case 1: return read8le((u8*)Bufo,is); + case 2: return read16le((u16*)Bufo,is); + case 4: return read32le((u32*)Bufo,is); + case 8: return read64le((u64*)Bufo,is); + default: + return 0; + } +} + + int read8le(u8 *Bufo, EMUFILE*is); int read16le(u16 *Bufo, EMUFILE*is); inline int read16le(s16 *Bufo, EMUFILE*is) { return read16le((u16*)Bufo,is); } diff --git a/desmume/src/registers.h b/desmume/src/registers.h index f9060214d..362b13df6 100644 --- a/desmume/src/registers.h +++ b/desmume/src/registers.h @@ -78,22 +78,40 @@ #define REG_DISPA_MASTERBRIGHT 0x0400006C // DMA +#define _REG_DMA_CONTROL_MIN 0x040000B0 #define REG_DMA0SAD 0x040000B0 +#define REG_DMA0SADL 0x040000B0 +#define REG_DMA0SADH 0x040000B2 #define REG_DMA0DAD 0x040000B4 +#define REG_DMA0DADL 0x040000B4 +#define REG_DMA0DADH 0x040000B6 #define REG_DMA0CNTL 0x040000B8 #define REG_DMA0CNTH 0x040000BA #define REG_DMA1SAD 0x040000BC +#define REG_DMA1SADL 0x040000BC +#define REG_DMA1SADH 0x040000BE #define REG_DMA1DAD 0x040000C0 +#define REG_DMA1DADL 0x040000C0 +#define REG_DMA1DADH 0x040000C2 #define REG_DMA1CNTL 0x040000C4 #define REG_DMA1CNTH 0x040000C6 #define REG_DMA2SAD 0x040000C8 +#define REG_DMA2SADL 0x040000C8 +#define REG_DMA2SADH 0x040000CA #define REG_DMA2DAD 0x040000CC +#define REG_DMA2DADL 0x040000CC +#define REG_DMA2DADH 0x040000CE #define REG_DMA2CNTL 0x040000D0 #define REG_DMA2CNTH 0x040000D2 #define REG_DMA3SAD 0x040000D4 +#define REG_DMA3SADL 0x040000D4 +#define REG_DMA3SADH 0x040000D6 #define REG_DMA3DAD 0x040000D8 +#define REG_DMA3DADL 0x040000D8 +#define REG_DMA3DADH 0x040000DA #define REG_DMA3CNTL 0x040000DC #define REG_DMA3CNTH 0x040000DE +#define _REG_DMA_CONTROL_MAX 0x040000DF #define REG_DMA0FILL 0x040000E0 #define REG_DMA1FILL 0x040000E4 #define REG_DMA2FILL 0x040000E8 diff --git a/desmume/src/saves.cpp b/desmume/src/saves.cpp index be1fa9001..daa253646 100644 --- a/desmume/src/saves.cpp +++ b/desmume/src/saves.cpp @@ -24,6 +24,7 @@ #include #endif #include +#include #include #include #include @@ -269,8 +270,14 @@ static void mmu_savestate(EMUFILE* os) u32 version = 3; write32le(version,os); - //newer savefile system: + //version 2: MMU_new.backupDevice.save_state(os); + + //version 3: + MMU_new.gxstat.savestate(os); + for(int i=0;i<2;i++) + for(int j=0;j<4;j++) + MMU_new.dma[i][j].savestate(os); MMU_timing.arm9codeFetch.savestate(os, version); MMU_timing.arm9dataFetch.savestate(os, version); @@ -423,11 +430,16 @@ static bool mmu_loadstate(EMUFILE* is, int size) if(version < 2) return true; - //newer savefile system: bool ok = MMU_new.backupDevice.load_state(is); if(version < 3) - return ok; + return true; + + ok &= MMU_new.gxstat.loadstate(is); + + for(int i=0;i<2;i++) + for(int j=0;j<4;j++) + ok &= MMU_new.dma[i][j].loadstate(is); ok &= MMU_timing.arm9codeFetch.loadstate(is, version); ok &= MMU_timing.arm9dataFetch.loadstate(is, version); @@ -800,6 +812,10 @@ static int SubWrite(EMUFILE* os, const SFORMAT *sf) { uint32 acc=0; +#ifdef DEBUG + std::set keyset; +#endif + const SFORMAT* temp = sf; while(temp->v) { const SFORMAT* seek = sf; @@ -839,6 +855,16 @@ static int SubWrite(EMUFILE* os, const SFORMAT *sf) write32le(sf->size,os); write32le(sf->count,os); + #ifdef DEBUG + //make sure we dont dup any keys + if(keyset.find(sf->desc) != keyset.end()) + { + printf("duplicate save key!\n"); + assert(false); + } + keyset.insert(sf->desc); + #endif + #ifdef LOCAL_LE // no need to ever loop one at a time if not flipping byte order os->fwrite((char *)sf->v,size*count); diff --git a/desmume/src/windows/IORegView.cpp b/desmume/src/windows/IORegView.cpp index ae90adf60..3cffb64b7 100644 --- a/desmume/src/windows/IORegView.cpp +++ b/desmume/src/windows/IORegView.cpp @@ -186,6 +186,29 @@ IOReg IORegs9[] = { {"Mtx stack busy",14,1},{"Mtx stack over/under-flow",15,1},{"GX FIFO level",16,9},{"GX FIFO full",24,1}, {"GX FIFO less than half full",25,1},{"GX FIFO empty",26,1},{"GX busy",27,1},{"GX FIFO IRQ condition",30,2}}}, + {CatBegin, "DMA registers", 0, 4, 0, {{0}}}, + {MMIOReg, "DMA0SAD", REG_DMA0SAD, 4, 1, {{"Value",0,28}}}, + {MMIOReg, "DMA0DAD", REG_DMA0DAD, 4, 1, {{"Value",0,28}}}, + {MMIOReg, "DMA0CNT", REG_DMA0CNTL, 4, 8, {{"Word Count",0,21}, {"Dest update method",21,2}, {"Src update method",23,2}, {"Repeat Flag",25,1}, {"32bit Width Enable",26,1},{"Start Mode",27,3}, {"IRQ Enable",30,1}, {"Enabled",31,1}}}, + {MMIOReg, "DMA1SAD", REG_DMA1SAD, 4, 1, {{"Value",0,28}}}, + {MMIOReg, "DMA1DAD", REG_DMA1DAD, 4, 1, {{"Value",0,28}}}, + {MMIOReg, "DMA1CNT", REG_DMA1CNTL, 4, 8, {{"Word Count",0,21}, {"Dest update method",21,2}, {"Src update method",23,2}, {"Repeat Flag",25,1}, {"32bit Width Enable",26,1},{"Start Mode",27,3}, {"IRQ Enable",30,1}, {"Enabled",31,1}}}, + {MMIOReg, "DMA2SAD", REG_DMA2SAD, 4, 1, {{"Value",0,28}}}, + {MMIOReg, "DMA2DAD", REG_DMA2DAD, 4, 1, {{"Value",0,28}}}, + {MMIOReg, "DMA2CNT", REG_DMA2CNTL, 4, 8, {{"Word Count",0,21}, {"Dest update method",21,2}, {"Src update method",23,2}, {"Repeat Flag",25,1}, {"32bit Width Enable",26,1},{"Start Mode",27,3}, {"IRQ Enable",30,1}, {"Enabled",31,1}}}, + {MMIOReg, "DMA3SAD", REG_DMA3SAD, 4, 1, {{"Value",0,28}}}, + {MMIOReg, "DMA3DAD", REG_DMA3DAD, 4, 1, {{"Value",0,28}}}, + {MMIOReg, "DMA3CNT", REG_DMA3CNTL, 4, 8, {{"Word Count",0,21}, {"Dest update method",21,2}, {"Src update method",23,2}, {"Repeat Flag",25,1}, {"32bit Width Enable",26,1},{"Start Mode",27,3}, {"IRQ Enable",30,1}, {"Enabled",31,1}}}, + + + /*{CatBegin, "Video engine B registers", 0, 36, 0, {{0}}}, + {MMIOReg, "[B]DISPCNT", 0x04001000, 4, 18, {{"BG mode",0,3},{"Tile OBJ mapping",4,1},{"Bitmap OBJ 2D size",5,1},{"Bitmap OBJ mapping",6,1}, + {"Forced blank",7,1},{"Display BG0",8,1},{"Display BG1",9,1},{"Display BG2",10,1}, + {"Display BG3",11,1},{"Display OBJ",12,1},{"Display window 0",13,1},{"Display window 1",14,1}, + {"Display OBJ window",15,1},{"Display mode",16,2},{"Tile OBJ 1D boundary",20,2},{"Process OBJs during HBlank",23,1}, + {"Enable BG ext. palettes",30,1},{"Enable OBJ ext. palettes",31,1}}}, + {MMIOReg, "[B]BG0CNT", 0x04001008, 2, 7, {{"Priority",0,2},{"Character base",2,4},{"Mosaic",6,1},{"Palette mode",7,1}, + */ {CatBegin, "IPC registers", 0, 2, 0, {{0}}}, {MMIOReg, "IPCSYNC", 0x04000180, 2, 3, {{"Data input from remote",0,4},{"Data output to remote",8,4},{"Enable IRQ from remote",14,1}}}, @@ -234,6 +257,21 @@ IOReg IORegs7[] = { {"IPC recv FIFO not empty",18,1},{"Gamecard transfer",19,1},{"Gamecard IREQ_MC",20,1},{"Lid opened",22,1}, {"SPI bus",23,1},{"Wifi",24,1}}}, + {CatBegin, "DMA registers", 0, 4, 0, {{0}}}, + {MMIOReg, "DMA0SAD", REG_DMA0SAD, 4, 1, {{"Value",0,27}}}, + {MMIOReg, "DMA0DAD", REG_DMA0DAD, 4, 1, {{"Value",0,27}}}, + {MMIOReg, "DMA0CNT", REG_DMA0CNTL, 4, 8, {{"Word Count",0,21}, {"Dest update method",21,2}, {"Src update method",23,2}, {"Repeat Flag",25,1}, {"32bit Width Enable",26,1},{"Start Mode",28,2}, {"IRQ Enable",30,1}, {"Enabled",31,1}}}, + {MMIOReg, "DMA1SAD", REG_DMA1SAD, 4, 1, {{"Value",0,27}}}, + {MMIOReg, "DMA1DAD", REG_DMA1DAD, 4, 1, {{"Value",0,27}}}, + {MMIOReg, "DMA1CNT", REG_DMA1CNTL, 4, 8, {{"Word Count",0,21}, {"Dest update method",21,2}, {"Src update method",23,2}, {"Repeat Flag",25,1}, {"32bit Width Enable",26,1},{"Start Mode",28,2}, {"IRQ Enable",30,1}, {"Enabled",31,1}}}, + {MMIOReg, "DMA2SAD", REG_DMA2SAD, 4, 1, {{"Value",0,27}}}, + {MMIOReg, "DMA2DAD", REG_DMA2DAD, 4, 1, {{"Value",0,27}}}, + {MMIOReg, "DMA2CNT", REG_DMA2CNTL, 4, 8, {{"Word Count",0,21}, {"Dest update method",21,2}, {"Src update method",23,2}, {"Repeat Flag",25,1}, {"32bit Width Enable",26,1},{"Start Mode",28,2}, {"IRQ Enable",30,1}, {"Enabled",31,1}}}, + {MMIOReg, "DMA3SAD", REG_DMA3SAD, 4, 1, {{"Value",0,27}}}, + {MMIOReg, "DMA3DAD", REG_DMA3DAD, 4, 1, {{"Value",0,27}}}, + {MMIOReg, "DMA3CNT", REG_DMA3CNTL, 4, 8, {{"Word Count",0,21}, {"Dest update method",21,2}, {"Src update method",23,2}, {"Repeat Flag",25,1}, {"32bit Width Enable",26,1},{"Start Mode",28,2}, {"IRQ Enable",30,1}, {"Enabled",31,1}}}, + + {ListEnd, 0, 0, 0, 0, {{0}}} }; @@ -242,6 +280,20 @@ IOReg* IORegs[2] = {IORegs9, IORegs7}; static const int kXMargin = 5; static const int kYMargin = 1; +typedef std::vector TIORegViewList; +static TIORegViewList liveIORegViews; + +void RefreshAllIORegViews() +{ + //TODO - this is a placeholder for a more robust system for signalling changes to the IORegView for immediate display. + //individual windows should subscribe to this service (so it doesnt always waste time) + for(TIORegViewList::iterator it(liveIORegViews.begin()); it != liveIORegViews.end(); ++it) + { + (*it)->Refresh(); + UpdateWindow((*it)->hWnd); //TODO - base class should have this functionality + } +} + /*--------------------------------------------------------------------------*/ CIORegView::CIORegView() @@ -250,12 +302,15 @@ CIORegView::CIORegView() , Reg(0) , yoff(0) { + liveIORegViews.push_back(this); } CIORegView::~CIORegView() { DestroyWindow(hWnd); UnregWndClass("DeSmuME_IORegView"); + //TODO - is this thread safe? which thread do these calls come from + liveIORegViews.erase(std::find(liveIORegViews.begin(),liveIORegViews.end(),this)); } /*--------------------------------------------------------------------------*/ @@ -609,6 +664,7 @@ LRESULT CALLBACK IORegView_Proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar rbBand.hwndChild = wnd->hCPUCombo; rbBand.cxMinChild = 0; rbBand.cyMinChild = rc.bottom - rc.top; + rbBand.cx = 100; SendMessage(wnd->hRebar, RB_INSERTBAND, (WPARAM)-1, (LPARAM)&rbBand); GetWindowRect(wnd->hRegCombo, &rc); @@ -642,7 +698,7 @@ LRESULT CALLBACK IORegView_Proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar SetWindowPos(wnd->hScrollbar, NULL, rc.right-wnd->vsbWidth, wnd->rebarHeight, wnd->vsbWidth, rc.bottom-wnd->rebarHeight, SWP_NOZORDER); // Keep the first rebar band width to a reasonable value - SendMessage(wnd->hRebar, RB_SETBANDWIDTH, 0, 60); + SendMessage(wnd->hRebar, RB_SETBANDWIDTH, 0, 100); GetClientRect(hWnd, &rc); wnd->maxlines = (rc.bottom - wnd->rebarHeight) / wnd->lineheight; diff --git a/desmume/src/windows/IORegView.h b/desmume/src/windows/IORegView.h index 49a93008e..f26bfa54b 100644 --- a/desmume/src/windows/IORegView.h +++ b/desmume/src/windows/IORegView.h @@ -23,9 +23,12 @@ #define IO_REG_H #include "../common.h" +#include "CWindow.h" LRESULT CALLBACK IORegView_Proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); +void RefreshAllIORegViews(); + class CIORegView : public CToolWindow { public: diff --git a/desmume/src/windows/main.cpp b/desmume/src/windows/main.cpp index 0fac2a4c3..f9392e772 100644 --- a/desmume/src/windows/main.cpp +++ b/desmume/src/windows/main.cpp @@ -1267,7 +1267,7 @@ static void StepRunLoop_Paused() static void StepRunLoop_User() { - const int kFramesPerToolUpdate = 6; + const int kFramesPerToolUpdate = 1; Hud.fps = mainLoopData.fps; Hud.fps3d = mainLoopData.fps3d;