From c4be07bc875b617d4890d219c8de0d4d895d76a7 Mon Sep 17 00:00:00 2001 From: nitsuja Date: Sun, 9 Aug 2009 22:31:59 +0000 Subject: [PATCH] disp3dcnt fix (fixes missing zx advent sprites, and I don't know what else) (possibly incomplete though), 32-bit poly+vert-count read fix, disassembler stack corruption fix, savestate fix with wifi sequencer, made wifi random not use rand() since that could potentially cause desyncs, did some probably-minor savestate optimizations --- desmume/src/Disassembler.cpp | 2 +- desmume/src/MMU.cpp | 7 ++- desmume/src/NDSSystem.cpp | 10 ++-- desmume/src/gfx3d.cpp | 2 +- desmume/src/saves.cpp | 89 ++++++++++++++++++++++++++---------- desmume/src/wifi.cpp | 11 ++++- 6 files changed, 88 insertions(+), 33 deletions(-) diff --git a/desmume/src/Disassembler.cpp b/desmume/src/Disassembler.cpp index 11f9d319c..47d6534f8 100644 --- a/desmume/src/Disassembler.cpp +++ b/desmume/src/Disassembler.cpp @@ -265,7 +265,7 @@ const char MSR_FIELD[16][5] = { }\ }\ }\ - lreg[strlen(lreg)-1]='\0'; + if(*lreg) lreg[strlen(lreg)-1]='\0'; static char * OP_UND(u32 adr, u32 i, char * txt) { diff --git a/desmume/src/MMU.cpp b/desmume/src/MMU.cpp index b501e9e82..2a711a32b 100644 --- a/desmume/src/MMU.cpp +++ b/desmume/src/MMU.cpp @@ -1702,6 +1702,7 @@ void FASTCALL _MMU_ARM9_write08(u32 adr, u8 val) case REG_DISPA_DISP3DCNT+1: { u32 &disp3dcnt = MainScreen.gpu->dispx_st->dispA_DISP3DCNT.val; + val = (val & ~0x30) | (~val & ((disp3dcnt>>8) & 0x30)); // bits 12,13 are ack bits disp3dcnt = (disp3dcnt&0x00FF) | (val<<8); gfx3d_Control(disp3dcnt); break; @@ -1931,7 +1932,9 @@ void FASTCALL _MMU_ARM9_write16(u32 adr, u16 val) case REG_DISPA_DISP3DCNT: { - MainScreen.gpu->dispx_st->dispA_DISP3DCNT.val = val; + u32 &disp3dcnt = MainScreen.gpu->dispx_st->dispA_DISP3DCNT.val; + val = (val & ~0x3000) | (~val & (disp3dcnt & 0x3000)); // bits 12,13 are ack bits + disp3dcnt = val; gfx3d_Control(val); break; } @@ -2896,7 +2899,7 @@ u32 FASTCALL _MMU_ARM9_read32(u32 adr) case 0x4000604: { - return (gfx3d_GetNumPolys()) & ((gfx3d_GetNumVertex()) << 16); + return (gfx3d_GetNumPolys()) | ((gfx3d_GetNumVertex()) << 16); //LOG ("read32 - RAM_COUNT -> 0x%X", ((u32 *)(MMU.MMU_MEM[ARMCPU_ARM9][(adr>>20)&0xFF]))[(adr&MMU.MMU_MASK[ARMCPU_ARM9][(adr>>20)&0xFF])>>2]); } diff --git a/desmume/src/NDSSystem.cpp b/desmume/src/NDSSystem.cpp index b158c2b96..b75148b06 100644 --- a/desmume/src/NDSSystem.cpp +++ b/desmume/src/NDSSystem.cpp @@ -1766,6 +1766,7 @@ struct Sequencer divider.save(os); sqrtunit.save(os); gxfifo.save(os); + wifi.save(os); #define SAVE(I,X,Y) I##_##X##_##Y .save(os); SAVE(timer,0,0); SAVE(timer,0,1); SAVE(timer,0,2); SAVE(timer,0,3); SAVE(timer,1,0); SAVE(timer,1,1); SAVE(timer,1,2); SAVE(timer,1,3); @@ -1774,7 +1775,7 @@ struct Sequencer #undef SAVE } - bool load(std::istream* is) + bool load(std::istream* is, int version) { if(read64le(&nds_timer,is) != 1) return false; if(read64le(&nds_arm9_timer,is) != 1) return false; @@ -1783,6 +1784,7 @@ struct Sequencer if(!divider.load(is)) return false; if(!sqrtunit.load(is)) return false; if(!gxfifo.load(is)) return false; + if(version >= 1) if(!wifi.load(is)) return false; #define LOAD(I,X,Y) if(!I##_##X##_##Y .load(is)) return false; LOAD(timer,0,0); LOAD(timer,0,1); LOAD(timer,0,2); LOAD(timer,0,3); LOAD(timer,1,0); LOAD(timer,1,1); LOAD(timer,1,2); LOAD(timer,1,3); @@ -2082,7 +2084,7 @@ void execHardware_interrupts(); void nds_savestate(std::ostream* os) { //version - write32le(0,os); + write32le(1,os); sequencer.save(os); } @@ -2093,9 +2095,9 @@ bool nds_loadstate(std::istream* is, int size) int version; if(read32le(&version,is) != 1) return false; - if(version != 0) return false; + if(version > 1) return false; - return sequencer.load(is); + return sequencer.load(is, version); } //#define LOG_ARM9 diff --git a/desmume/src/gfx3d.cpp b/desmume/src/gfx3d.cpp index 3f00911a3..9758915cf 100644 --- a/desmume/src/gfx3d.cpp +++ b/desmume/src/gfx3d.cpp @@ -2354,7 +2354,7 @@ void gfx3d_GetLineData15bpp(int line, u16** dst) //consider building a little state structure that looks exactly like this describes SFORMAT SF_GFX3D[]={ - //{ "GCTL", 4, 1, &control}, //this gets regenerated by the code i hate which regenerates gpu regs + { "GCTL", 4, 1, &control}, // no longer regenerated indirectly, see comment in loadstate() { "GPAT", 4, 1, &polyAttr}, { "GPAP", 4, 1, &polyAttrPending}, { "GINB", 4, 1, &inBegin}, diff --git a/desmume/src/saves.cpp b/desmume/src/saves.cpp index d4e5dc5dc..52d47926d 100644 --- a/desmume/src/saves.cpp +++ b/desmume/src/saves.cpp @@ -690,8 +690,11 @@ int sram_save (const char *file_name) { } -static const SFORMAT *CheckS(const SFORMAT *sf, u32 size, u32 count, char *desc) +// note: guessSF is so we don't have to do a linear search through the SFORMAT array every time +// in the (most common) case that we already know where the next entry is. +static const SFORMAT *CheckS(const SFORMAT *guessSF, const SFORMAT *firstSF, u32 size, u32 count, char *desc) { + const SFORMAT *sf = guessSF ? guessSF : firstSF; while(sf->v) { //NOT SUPPORTED RIGHT NOW @@ -709,7 +712,17 @@ static const SFORMAT *CheckS(const SFORMAT *sf, u32 size, u32 count, char *desc) return 0; return sf; } - sf++; + + // failed to find it, have to keep iterating + if(guessSF) + { + sf = firstSF; + guessSF = NULL; + } + else + { + sf++; + } } return 0; } @@ -717,7 +730,8 @@ static const SFORMAT *CheckS(const SFORMAT *sf, u32 size, u32 count, char *desc) static bool ReadStateChunk(std::istream* is, const SFORMAT *sf, int size) { - const SFORMAT *tmp; + const SFORMAT *tmp = NULL; + const SFORMAT *guessSF = NULL; int temp = is->tellg(); while(is->tellg()read((char *)tmp->v,sz*count); + #else if(sz == 1) { //special case: read a huge byte array is->read((char *)tmp->v,count); @@ -741,15 +759,17 @@ static bool ReadStateChunk(std::istream* is, const SFORMAT *sf, int size) for(unsigned int i=0;iread((char *)tmp->v + i*sz,sz); - - #ifndef LOCAL_LE - FlipByteOrder((u8*)tmp->v + i*sz,sz); - #endif + FlipByteOrder((u8*)tmp->v + i*sz,sz); } } + #endif + guessSF = tmp + 1; } else + { is->seekg(sz*count,std::ios::cur); + guessSF = NULL; + } } // while(...) return true; } @@ -799,24 +819,22 @@ static int SubWrite(std::ostream* os, const SFORMAT *sf) write32le(sf->size,os); write32le(sf->count,os); - if(size == 1) { + #ifdef LOCAL_LE + // no need to ever loop one at a time if not flipping byte order + os->write((char *)sf->v,size*count); + #else + if(sz == 1) { //special case: write a huge byte array os->write((char *)sf->v,count); } else { for(int i=0;iv + i*size, size); - #endif - + FlipByteOrder((u8*)sf->v + i*size, size); os->write((char*)sf->v + i*size,size); - //Now restore the original byte order. - #ifndef LOCAL_LE - FlipByteOrder((u8*)sf->v + i*size, size); - #endif + FlipByteOrder((u8*)sf->v + i*size, size); } } + #endif } sf++; } @@ -838,11 +856,32 @@ static int savestate_WriteChunk(std::ostream* os, int type, const SFORMAT *sf) return (bsize+8); } -//TODO TODO TODO TODO TODO TODO TODO -// - this is retarded. why not write placeholders for size and then write directly to the stream -//and then go back and fill them in static void savestate_WriteChunk(std::ostream* os, int type, void (*saveproc)(std::ostream* os)) { + u32 pos1 = os->tellp(); + + //write the type, size(placeholder), and data + write32le(type,os); + write32le(0,os); // <-- temporary write, re-written later + saveproc(os); + + //get the size + u32 pos2 = os->tellp(); + assert(pos2 != (u32)-1); // if this assert fails, saveproc did something bad + u32 size = (pos2 - pos1) - (2 * sizeof(u32)); + + //fill in the actual size + os->seekp(pos1 + sizeof(u32)); + write32le(size,os); + os->seekp(pos2); + +/* +// old version of this function, +// for reference in case the new one above starts misbehaving somehow: + + // - this is retarded. why not write placeholders for size and then write directly to the stream + //and then go back and fill them in + //get the size memorystream mstemp; saveproc(&mstemp); @@ -853,6 +892,7 @@ static void savestate_WriteChunk(std::ostream* os, int type, void (*saveproc)(st write32le(type,os); write32le(size,os); os->write(mstemp.buf(),size); +*/ } static void writechunks(std::ostream* os); @@ -996,7 +1036,8 @@ static bool ReadStateChunks(std::istream* is, s32 totalsize) ret=false; break; } - if(!ret) return false; + if(!ret) + return false; } done: @@ -1020,13 +1061,13 @@ static void loadstate() //_MMU_write16(i, _MMU_read16(i)); // for (int i = REG_BASE_DISPB; i<=REG_BASE_DISPB + 0x7F; i+=2) //_MMU_write16(i, _MMU_read16(i)); - static const u8 mainRegenAddr[] = {0x00,0x02,0x08,0x0a,0x0c,0x0e,0x40,0x42,0x44,0x46,0x48,0x4a,0x4c,0x50,0x52,0x54,0x60,0x64,0x66,0x6c}; + static const u8 mainRegenAddr[] = {0x00,0x02,0x08,0x0a,0x0c,0x0e,0x40,0x42,0x44,0x46,0x48,0x4a,0x4c,0x50,0x52,0x54,0x64,0x66,0x6c}; static const u8 subRegenAddr[] = {0x00,0x02,0x08,0x0a,0x0c,0x0e,0x40,0x42,0x44,0x46,0x48,0x4a,0x4c,0x50,0x52,0x54,0x6c}; for(u32 i=0;i(REG_BASE_DISPA+mainRegenAddr[i], _MMU_read16(REG_BASE_DISPA+mainRegenAddr[i])); for(u32 i=0;i(REG_BASE_DISPB+subRegenAddr[i], _MMU_read16(REG_BASE_DISPB+subRegenAddr[i])); - + // no need to restore 0x60 since control and MMU.ARM9_REG are both in the savestates, and restoring it could mess up the ack bits anyway SetupMMU(nds.debugConsole); } diff --git a/desmume/src/wifi.cpp b/desmume/src/wifi.cpp index a2cf76953..376994be6 100644 --- a/desmume/src/wifi.cpp +++ b/desmume/src/wifi.cpp @@ -1062,7 +1062,16 @@ u16 WIFI_read16(u32 address) return WIFI_getBB_DATA() ; case REG_WIFI_RANDOM: /* FIXME: random generator */ - return (rand() & 0x7FF); +// return (rand() & 0x7FF); // disabled (no wonder there were desyncs...) + + // probably not right, but it's better than using the unsaved and shared rand(). + // at the very least, rand() shouldn't be used when movieMode is active. + { + u16 returnValue = wifiMac.randomSeed; + wifiMac.randomSeed = (wifiMac.randomSeed & 1) ^ (((wifiMac.randomSeed << 1) & 0x7FE) | ((wifiMac.randomSeed >> 10) & 0x1)); + return returnValue; + } + return 0 ; case REG_WIFI_MAC0: case REG_WIFI_MAC1: