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
This commit is contained in:
parent
5e3cb11c83
commit
c4be07bc87
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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},
|
||||
|
|
|
@ -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()<temp+size)
|
||||
|
@ -732,8 +746,12 @@ static bool ReadStateChunk(std::istream* is, const SFORMAT *sf, int size)
|
|||
if(!read32le(&sz,is)) return false;
|
||||
if(!read32le(&count,is)) return false;
|
||||
|
||||
if((tmp=CheckS(sf,sz,count,toa)))
|
||||
if((tmp=CheckS(guessSF,sf,sz,count,toa)))
|
||||
{
|
||||
#ifdef LOCAL_LE
|
||||
// no need to ever loop one at a time if not flipping byte order
|
||||
is->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;i<count;i++)
|
||||
{
|
||||
is->read((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;i<count;i++) {
|
||||
|
||||
#ifndef LOCAL_LE
|
||||
FlipByteOrder((u8*)sf->v + 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<ARMCPU_ARM9>(i, _MMU_read16<ARMCPU_ARM9>(i));
|
||||
// for (int i = REG_BASE_DISPB; i<=REG_BASE_DISPB + 0x7F; i+=2)
|
||||
//_MMU_write16<ARMCPU_ARM9>(i, _MMU_read16<ARMCPU_ARM9>(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<ARRAY_SIZE(mainRegenAddr);i++)
|
||||
_MMU_write16<ARMCPU_ARM9>(REG_BASE_DISPA+mainRegenAddr[i], _MMU_read16<ARMCPU_ARM9>(REG_BASE_DISPA+mainRegenAddr[i]));
|
||||
for(u32 i=0;i<ARRAY_SIZE(subRegenAddr);i++)
|
||||
_MMU_write16<ARMCPU_ARM9>(REG_BASE_DISPB+subRegenAddr[i], _MMU_read16<ARMCPU_ARM9>(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);
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue