merge moar
This commit is contained in:
commit
b44570eba1
|
@ -1,3 +1,4 @@
|
|||
build
|
||||
bin
|
||||
obj
|
||||
*.depend
|
||||
|
|
|
@ -212,7 +212,8 @@ public:
|
|||
void UpdateDTCMSetting();
|
||||
void UpdateITCMSetting();
|
||||
|
||||
void UpdatePURegions();
|
||||
void UpdatePURegion(u32 n);
|
||||
void UpdatePURegions(bool update_all);
|
||||
|
||||
u32 RandomLineIndex();
|
||||
|
||||
|
|
341
src/CP15.cpp
341
src/CP15.cpp
|
@ -60,7 +60,7 @@ void ARMv5::CP15Reset()
|
|||
PU_DataRW = 0;
|
||||
|
||||
memset(PU_Region, 0, 8*sizeof(u32));
|
||||
UpdatePURegions();
|
||||
UpdatePURegions(true);
|
||||
|
||||
CurICacheLine = NULL;
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ void ARMv5::CP15DoSavestate(Savestate* file)
|
|||
{
|
||||
UpdateDTCMSetting();
|
||||
UpdateITCMSetting();
|
||||
UpdatePURegions();
|
||||
UpdatePURegions(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -126,7 +126,103 @@ void ARMv5::UpdateITCMSetting()
|
|||
}
|
||||
|
||||
|
||||
void ARMv5::UpdatePURegions()
|
||||
// covers updates to a specific PU region's cache/etc settings
|
||||
// (not to the region range/enabled status)
|
||||
void ARMv5::UpdatePURegion(u32 n)
|
||||
{
|
||||
u32 coderw = (PU_CodeRW >> (4*n)) & 0xF;
|
||||
u32 datarw = (PU_DataRW >> (4*n)) & 0xF;
|
||||
|
||||
u32 codecache, datacache, datawrite;
|
||||
|
||||
// datacache/datawrite
|
||||
// 0/0: goes to memory
|
||||
// 0/1: goes to memory
|
||||
// 1/0: goes to memory and cache
|
||||
// 1/1: goes to cache
|
||||
|
||||
if (CP15Control & (1<<12))
|
||||
codecache = (PU_CodeCacheable >> n) & 0x1;
|
||||
else
|
||||
codecache = 0;
|
||||
|
||||
if (CP15Control & (1<<2))
|
||||
{
|
||||
datacache = (PU_DataCacheable >> n) & 0x1;
|
||||
datawrite = (PU_DataCacheWrite >> n) & 0x1;
|
||||
}
|
||||
else
|
||||
{
|
||||
datacache = 0;
|
||||
datawrite = 0;
|
||||
}
|
||||
|
||||
u32 rgn = PU_Region[n];
|
||||
if (!(rgn & (1<<0)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
u32 start = rgn >> 12;
|
||||
u32 sz = 2 << ((rgn >> 1) & 0x1F);
|
||||
u32 end = start + (sz >> 12);
|
||||
// TODO: check alignment of start
|
||||
|
||||
u8 usermask = 0;
|
||||
u8 privmask = 0;
|
||||
|
||||
switch (datarw)
|
||||
{
|
||||
case 0: break;
|
||||
case 1: privmask |= 0x03; break;
|
||||
case 2: privmask |= 0x03; usermask |= 0x01; break;
|
||||
case 3: privmask |= 0x03; usermask |= 0x03; break;
|
||||
case 5: privmask |= 0x01; break;
|
||||
case 6: privmask |= 0x01; usermask |= 0x01; break;
|
||||
default: printf("!! BAD DATARW VALUE %d\n", datarw&0xF);
|
||||
}
|
||||
|
||||
switch (coderw)
|
||||
{
|
||||
case 0: break;
|
||||
case 1: privmask |= 0x04; break;
|
||||
case 2: privmask |= 0x04; usermask |= 0x04; break;
|
||||
case 3: privmask |= 0x04; usermask |= 0x04; break;
|
||||
case 5: privmask |= 0x04; break;
|
||||
case 6: privmask |= 0x04; usermask |= 0x04; break;
|
||||
default: printf("!! BAD CODERW VALUE %d\n", datarw&0xF);
|
||||
}
|
||||
|
||||
if (datacache & 0x1)
|
||||
{
|
||||
privmask |= 0x10;
|
||||
usermask |= 0x10;
|
||||
|
||||
if (datawrite & 0x1)
|
||||
{
|
||||
privmask |= 0x20;
|
||||
usermask |= 0x20;
|
||||
}
|
||||
}
|
||||
|
||||
if (codecache & 0x1)
|
||||
{
|
||||
privmask |= 0x40;
|
||||
usermask |= 0x40;
|
||||
}
|
||||
|
||||
//printf("PU region %d: %08X-%08X, user=%02X priv=%02X\n", n, start<<12, end<<12, usermask, privmask);
|
||||
|
||||
for (u32 i = start; i < end; i++)
|
||||
{
|
||||
PU_UserMap[i] = usermask;
|
||||
PU_PrivMap[i] = privmask;
|
||||
}
|
||||
|
||||
UpdateRegionTimings(start<<12, end<<12);
|
||||
}
|
||||
|
||||
void ARMv5::UpdatePURegions(bool update_all)
|
||||
{
|
||||
if (!(CP15Control & (1<<0)))
|
||||
{
|
||||
|
@ -139,121 +235,24 @@ void ARMv5::UpdatePURegions()
|
|||
memset(PU_UserMap, mask, 0x100000);
|
||||
memset(PU_PrivMap, mask, 0x100000);
|
||||
|
||||
UpdateRegionTimings(0x00000000, 0xFFFFFFFF);
|
||||
return;
|
||||
}
|
||||
|
||||
memset(PU_UserMap, 0, 0x100000);
|
||||
memset(PU_PrivMap, 0, 0x100000);
|
||||
|
||||
u32 coderw = PU_CodeRW;
|
||||
u32 datarw = PU_DataRW;
|
||||
|
||||
u32 codecache, datacache, datawrite;
|
||||
|
||||
// datacache/datawrite
|
||||
// 0/0: goes to memory
|
||||
// 0/1: goes to memory
|
||||
// 1/0: goes to memory and cache
|
||||
// 1/1: goes to cache
|
||||
|
||||
if (CP15Control & (1<<12))
|
||||
codecache = PU_CodeCacheable;
|
||||
else
|
||||
codecache = 0;
|
||||
|
||||
if (CP15Control & (1<<2))
|
||||
if (update_all)
|
||||
{
|
||||
datacache = PU_DataCacheable;
|
||||
datawrite = PU_DataCacheWrite;
|
||||
}
|
||||
else
|
||||
{
|
||||
datacache = 0;
|
||||
datawrite = 0;
|
||||
memset(PU_UserMap, 0, 0x100000);
|
||||
memset(PU_PrivMap, 0, 0x100000);
|
||||
}
|
||||
|
||||
for (int n = 0; n < 8; n++)
|
||||
{
|
||||
u32 rgn = PU_Region[n];
|
||||
if (!(rgn & (1<<0)))
|
||||
{
|
||||
coderw >>= 4;
|
||||
datarw >>= 4;
|
||||
codecache >>= 1;
|
||||
datacache >>= 1;
|
||||
datawrite >>= 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
u32 start = rgn >> 12;
|
||||
u32 sz = 2 << ((rgn >> 1) & 0x1F);
|
||||
u32 end = start + (sz >> 12);
|
||||
// TODO: check alignment of start
|
||||
|
||||
u8 usermask = 0;
|
||||
u8 privmask = 0;
|
||||
|
||||
switch (datarw & 0xF)
|
||||
{
|
||||
case 0: break;
|
||||
case 1: privmask |= 0x03; break;
|
||||
case 2: privmask |= 0x03; usermask |= 0x01; break;
|
||||
case 3: privmask |= 0x03; usermask |= 0x03; break;
|
||||
case 5: privmask |= 0x01; break;
|
||||
case 6: privmask |= 0x01; usermask |= 0x01; break;
|
||||
default: printf("!! BAD DATARW VALUE %d\n", datarw&0xF);
|
||||
}
|
||||
|
||||
switch (coderw & 0xF)
|
||||
{
|
||||
case 0: break;
|
||||
case 1: privmask |= 0x04; break;
|
||||
case 2: privmask |= 0x04; usermask |= 0x04; break;
|
||||
case 3: privmask |= 0x04; usermask |= 0x04; break;
|
||||
case 5: privmask |= 0x04; break;
|
||||
case 6: privmask |= 0x04; usermask |= 0x04; break;
|
||||
default: printf("!! BAD CODERW VALUE %d\n", datarw&0xF);
|
||||
}
|
||||
|
||||
if (datacache & 0x1)
|
||||
{
|
||||
privmask |= 0x10;
|
||||
usermask |= 0x10;
|
||||
|
||||
if (datawrite & 0x1)
|
||||
{
|
||||
privmask |= 0x20;
|
||||
usermask |= 0x20;
|
||||
}
|
||||
}
|
||||
|
||||
if (codecache & 0x1)
|
||||
{
|
||||
privmask |= 0x40;
|
||||
usermask |= 0x40;
|
||||
}
|
||||
|
||||
printf("PU region %d: %08X-%08X, user=%02X priv=%02X\n", n, start<<12, end<<12, usermask, privmask);
|
||||
|
||||
for (u32 i = start; i < end; i++)
|
||||
{
|
||||
PU_UserMap[i] = usermask;
|
||||
PU_PrivMap[i] = privmask;
|
||||
}
|
||||
|
||||
coderw >>= 4;
|
||||
datarw >>= 4;
|
||||
codecache >>= 1;
|
||||
datacache >>= 1;
|
||||
datawrite >>= 1;
|
||||
|
||||
// TODO: this will not be enough if they change their PU regions after the intial setup
|
||||
//UpdateRegionTimings(start<<12, end<<12);
|
||||
UpdatePURegion(n);
|
||||
}
|
||||
|
||||
// TODO: this is way unoptimized
|
||||
// should be okay unless the game keeps changing shit, tho
|
||||
UpdateRegionTimings(0x00000000, 0xFFFFFFFF);
|
||||
if (update_all) UpdateRegionTimings(0x00000000, 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
void ARMv5::UpdateRegionTimings(u32 addrstart, u32 addrend)
|
||||
|
@ -303,7 +302,6 @@ u32 ARMv5::RandomLineIndex()
|
|||
return (RNGSeed >> 17) & 0x3;
|
||||
}
|
||||
|
||||
int zog=1;
|
||||
void ARMv5::ICacheLookup(u32 addr)
|
||||
{
|
||||
u32 tag = addr & 0xFFFFF800;
|
||||
|
@ -312,25 +310,25 @@ void ARMv5::ICacheLookup(u32 addr)
|
|||
id <<= 2;
|
||||
if (ICacheTags[id+0] == tag)
|
||||
{
|
||||
CodeCycles = 1;zog=1;
|
||||
CodeCycles = 1;
|
||||
CurICacheLine = &ICache[(id+0) << 5];
|
||||
return;
|
||||
}
|
||||
if (ICacheTags[id+1] == tag)
|
||||
{
|
||||
CodeCycles = 1;zog=2;
|
||||
CodeCycles = 1;
|
||||
CurICacheLine = &ICache[(id+1) << 5];
|
||||
return;
|
||||
}
|
||||
if (ICacheTags[id+2] == tag)
|
||||
{
|
||||
CodeCycles = 1;zog=3;
|
||||
CodeCycles = 1;
|
||||
CurICacheLine = &ICache[(id+2) << 5];
|
||||
return;
|
||||
}
|
||||
if (ICacheTags[id+3] == tag)
|
||||
{
|
||||
CodeCycles = 1;zog=4;
|
||||
CodeCycles = 1;
|
||||
CurICacheLine = &ICache[(id+3) << 5];
|
||||
return;
|
||||
}
|
||||
|
@ -418,10 +416,13 @@ void ARMv5::CP15Write(u32 id, u32 val)
|
|||
val &= 0x000FF085;
|
||||
CP15Control &= ~0x000FF085;
|
||||
CP15Control |= val;
|
||||
printf("CP15Control = %08X (%08X->%08X)\n", CP15Control, old, val);
|
||||
//printf("CP15Control = %08X (%08X->%08X)\n", CP15Control, old, val);
|
||||
UpdateDTCMSetting();
|
||||
UpdateITCMSetting();
|
||||
if ((old & 0x1005) != (val & 0x1005)) UpdatePURegions();
|
||||
if ((old & 0x1005) != (val & 0x1005))
|
||||
{
|
||||
UpdatePURegions((old & 0x1) != (val & 0x1));
|
||||
}
|
||||
if (val & (1<<7)) printf("!!!! ARM9 BIG ENDIAN MODE. VERY BAD. SHIT GONNA ASPLODE NOW\n");
|
||||
if (val & (1<<13)) ExceptionBase = 0xFFFF0000;
|
||||
else ExceptionBase = 0x00000000;
|
||||
|
@ -430,63 +431,100 @@ void ARMv5::CP15Write(u32 id, u32 val)
|
|||
|
||||
|
||||
case 0x200: // data cacheable
|
||||
PU_DataCacheable = val;
|
||||
printf("PU: DataCacheable=%08X\n", val);
|
||||
UpdatePURegions();
|
||||
{
|
||||
u32 diff = PU_DataCacheable ^ val;
|
||||
PU_DataCacheable = val;
|
||||
for (u32 i = 0; i < 8; i++)
|
||||
{
|
||||
if (diff & (1<<i)) UpdatePURegion(i);
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
case 0x201: // code cacheable
|
||||
PU_CodeCacheable = val;
|
||||
printf("PU: CodeCacheable=%08X\n", val);
|
||||
UpdatePURegions();
|
||||
{
|
||||
u32 diff = PU_CodeCacheable ^ val;
|
||||
PU_CodeCacheable = val;
|
||||
for (u32 i = 0; i < 8; i++)
|
||||
{
|
||||
if (diff & (1<<i)) UpdatePURegion(i);
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
|
||||
case 0x300: // data cache write-buffer
|
||||
PU_DataCacheWrite = val;
|
||||
printf("PU: DataCacheWrite=%08X\n", val);
|
||||
UpdatePURegions();
|
||||
{
|
||||
u32 diff = PU_DataCacheWrite ^ val;
|
||||
PU_DataCacheWrite = val;
|
||||
for (u32 i = 0; i < 8; i++)
|
||||
{
|
||||
if (diff & (1<<i)) UpdatePURegion(i);
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
|
||||
case 0x500: // legacy data permissions
|
||||
PU_DataRW = 0;
|
||||
PU_DataRW |= (val & 0x0003);
|
||||
PU_DataRW |= ((val & 0x000C) << 2);
|
||||
PU_DataRW |= ((val & 0x0030) << 4);
|
||||
PU_DataRW |= ((val & 0x00C0) << 6);
|
||||
PU_DataRW |= ((val & 0x0300) << 8);
|
||||
PU_DataRW |= ((val & 0x0C00) << 10);
|
||||
PU_DataRW |= ((val & 0x3000) << 12);
|
||||
PU_DataRW |= ((val & 0xC000) << 14);
|
||||
printf("PU: DataRW=%08X (legacy %08X)\n", PU_DataRW, val);
|
||||
UpdatePURegions();
|
||||
{
|
||||
u32 old = PU_DataRW;
|
||||
PU_DataRW = 0;
|
||||
PU_DataRW |= (val & 0x0003);
|
||||
PU_DataRW |= ((val & 0x000C) << 2);
|
||||
PU_DataRW |= ((val & 0x0030) << 4);
|
||||
PU_DataRW |= ((val & 0x00C0) << 6);
|
||||
PU_DataRW |= ((val & 0x0300) << 8);
|
||||
PU_DataRW |= ((val & 0x0C00) << 10);
|
||||
PU_DataRW |= ((val & 0x3000) << 12);
|
||||
PU_DataRW |= ((val & 0xC000) << 14);
|
||||
u32 diff = old ^ PU_DataRW;
|
||||
for (u32 i = 0; i < 8; i++)
|
||||
{
|
||||
if (diff & (0xF<<(i*4))) UpdatePURegion(i);
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
case 0x501: // legacy code permissions
|
||||
PU_CodeRW = 0;
|
||||
PU_CodeRW |= (val & 0x0003);
|
||||
PU_CodeRW |= ((val & 0x000C) << 2);
|
||||
PU_CodeRW |= ((val & 0x0030) << 4);
|
||||
PU_CodeRW |= ((val & 0x00C0) << 6);
|
||||
PU_CodeRW |= ((val & 0x0300) << 8);
|
||||
PU_CodeRW |= ((val & 0x0C00) << 10);
|
||||
PU_CodeRW |= ((val & 0x3000) << 12);
|
||||
PU_CodeRW |= ((val & 0xC000) << 14);
|
||||
printf("PU: CodeRW=%08X (legacy %08X)\n", PU_CodeRW, val);
|
||||
UpdatePURegions();
|
||||
{
|
||||
u32 old = PU_CodeRW;
|
||||
PU_CodeRW = 0;
|
||||
PU_CodeRW |= (val & 0x0003);
|
||||
PU_CodeRW |= ((val & 0x000C) << 2);
|
||||
PU_CodeRW |= ((val & 0x0030) << 4);
|
||||
PU_CodeRW |= ((val & 0x00C0) << 6);
|
||||
PU_CodeRW |= ((val & 0x0300) << 8);
|
||||
PU_CodeRW |= ((val & 0x0C00) << 10);
|
||||
PU_CodeRW |= ((val & 0x3000) << 12);
|
||||
PU_CodeRW |= ((val & 0xC000) << 14);
|
||||
u32 diff = old ^ PU_CodeRW;
|
||||
for (u32 i = 0; i < 8; i++)
|
||||
{
|
||||
if (diff & (0xF<<(i*4))) UpdatePURegion(i);
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
case 0x502: // data permissions
|
||||
PU_DataRW = val;
|
||||
printf("PU: DataRW=%08X\n", PU_DataRW);
|
||||
UpdatePURegions();
|
||||
{
|
||||
u32 diff = PU_DataRW ^ val;
|
||||
PU_DataRW = val;
|
||||
for (u32 i = 0; i < 8; i++)
|
||||
{
|
||||
if (diff & (0xF<<(i*4))) UpdatePURegion(i);
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
case 0x503: // code permissions
|
||||
PU_CodeRW = val;
|
||||
printf("PU: CodeRW=%08X\n", PU_CodeRW);
|
||||
UpdatePURegions();
|
||||
{
|
||||
u32 diff = PU_CodeRW ^ val;
|
||||
PU_CodeRW = val;
|
||||
for (u32 i = 0; i < 8; i++)
|
||||
{
|
||||
if (diff & (0xF<<(i*4))) UpdatePURegion(i);
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
|
||||
|
@ -511,7 +549,8 @@ void ARMv5::CP15Write(u32 id, u32 val)
|
|||
printf("%s, ", val&1 ? "enabled":"disabled");
|
||||
printf("%08X-", val&0xFFFFF000);
|
||||
printf("%08X\n", (val&0xFFFFF000)+(2<<((val&0x3E)>>1)));
|
||||
UpdatePURegions();
|
||||
// TODO: smarter region update for this?
|
||||
UpdatePURegions(true);
|
||||
return;
|
||||
|
||||
|
||||
|
|
|
@ -943,8 +943,8 @@ void GPU2D::VBlankEnd()
|
|||
BGMosaicYMax = BGMosaicSize[1];
|
||||
//OBJMosaicY = 0;
|
||||
//OBJMosaicYMax = OBJMosaicSize[1];
|
||||
OBJMosaicY = 0;
|
||||
OBJMosaicYCount = 0;
|
||||
//OBJMosaicY = 0;
|
||||
//OBJMosaicYCount = 0;
|
||||
|
||||
if (Accelerated)
|
||||
{
|
||||
|
@ -2238,6 +2238,13 @@ void GPU2D::DrawBG_Large(u32 line) // BG is always BG2
|
|||
BGYRefInternal[0] += rotD;
|
||||
}
|
||||
|
||||
// OBJ line buffer:
|
||||
// * bit0-15: color (bit15=1: direct color, bit15=0: palette index, bit12=0 to indicate extpal)
|
||||
// * bit16-17: BG-relative priority
|
||||
// * bit18: non-transparent sprite pixel exists here
|
||||
// * bit19: X mosaic should be applied here
|
||||
// * bit24-31: compositor flags
|
||||
|
||||
void GPU2D::ApplySpriteMosaicX()
|
||||
{
|
||||
// apply X mosaic if needed
|
||||
|
@ -2255,7 +2262,7 @@ void GPU2D::ApplySpriteMosaicX()
|
|||
continue;
|
||||
}
|
||||
|
||||
if ((!(OBJLine[i-1] & 0x100000)) || (CurOBJXMosaicTable[i] == 0))
|
||||
if ((OBJIndex[i] != OBJIndex[i-1]) || (CurOBJXMosaicTable[i] == 0))
|
||||
lastcolor = OBJLine[i];
|
||||
else
|
||||
OBJLine[i] = lastcolor;
|
||||
|
@ -2322,11 +2329,25 @@ void GPU2D::InterleaveSprites(u32 prio)
|
|||
|
||||
void GPU2D::DrawSprites(u32 line)
|
||||
{
|
||||
if (line == 0)
|
||||
{
|
||||
// reset those counters here
|
||||
// TODO: find out when those are supposed to be reset
|
||||
// it would make sense to reset them at the end of VBlank
|
||||
// however, sprites are rendered one scanline in advance
|
||||
// so they need to be reset a bit earlier
|
||||
|
||||
OBJMosaicY = 0;
|
||||
OBJMosaicYCount = 0;
|
||||
}
|
||||
|
||||
NumSprites = 0;
|
||||
memset(OBJLine, 0, 256*4);
|
||||
memset(OBJWindow, 0, 256);
|
||||
if (!(DispCnt & 0x1000)) return;
|
||||
|
||||
memset(OBJIndex, 0xFF, 256);
|
||||
|
||||
u16* oam = (u16*)&GPU::OAM[Num ? 0x400 : 0];
|
||||
|
||||
const s32 spritewidth[16] =
|
||||
|
@ -2355,6 +2376,15 @@ void GPU2D::DrawSprites(u32 line)
|
|||
|
||||
bool iswin = (((attrib[0] >> 10) & 0x3) == 2);
|
||||
|
||||
u32 sprline;
|
||||
if ((attrib[0] & 0x1000) && !iswin)
|
||||
{
|
||||
// apply Y mosaic
|
||||
sprline = OBJMosaicY;
|
||||
}
|
||||
else
|
||||
sprline = line;
|
||||
|
||||
if (attrib[0] & 0x0100)
|
||||
{
|
||||
u32 sizeparam = (attrib[0] >> 14) | ((attrib[1] & 0xC000) >> 12);
|
||||
|
@ -2370,7 +2400,7 @@ void GPU2D::DrawSprites(u32 line)
|
|||
}
|
||||
|
||||
u32 ypos = attrib[0] & 0xFF;
|
||||
ypos = (line - ypos) & 0xFF;
|
||||
ypos = (sprline - ypos) & 0xFF;
|
||||
if (ypos >= (u32)boundheight)
|
||||
continue;
|
||||
|
||||
|
@ -2380,7 +2410,7 @@ void GPU2D::DrawSprites(u32 line)
|
|||
|
||||
u32 rotparamgroup = (attrib[1] >> 9) & 0x1F;
|
||||
|
||||
DoDrawSprite(Rotscale, attrib, &oam[(rotparamgroup*16) + 3], boundwidth, boundheight, width, height, xpos, ypos);
|
||||
DoDrawSprite(Rotscale, sprnum, boundwidth, boundheight, width, height, xpos, ypos);
|
||||
|
||||
NumSprites++;
|
||||
}
|
||||
|
@ -2394,7 +2424,7 @@ void GPU2D::DrawSprites(u32 line)
|
|||
s32 height = spriteheight[sizeparam];
|
||||
|
||||
u32 ypos = attrib[0] & 0xFF;
|
||||
ypos = (line - ypos) & 0xFF;
|
||||
ypos = (sprline - ypos) & 0xFF;
|
||||
if (ypos >= (u32)height)
|
||||
continue;
|
||||
|
||||
|
@ -2402,11 +2432,7 @@ void GPU2D::DrawSprites(u32 line)
|
|||
if (xpos <= -width)
|
||||
continue;
|
||||
|
||||
// yflip
|
||||
if (attrib[1] & 0x2000)
|
||||
ypos = height-1 - ypos;
|
||||
|
||||
DoDrawSprite(Normal, attrib, width, xpos, ypos);
|
||||
DoDrawSprite(Normal, sprnum, width, height, xpos, ypos);
|
||||
|
||||
NumSprites++;
|
||||
}
|
||||
|
@ -2415,8 +2441,12 @@ void GPU2D::DrawSprites(u32 line)
|
|||
}
|
||||
|
||||
template<bool window>
|
||||
void GPU2D::DrawSprite_Rotscale(u16* attrib, u16* rotparams, u32 boundwidth, u32 boundheight, u32 width, u32 height, s32 xpos, s32 ypos)
|
||||
void GPU2D::DrawSprite_Rotscale(u32 num, u32 boundwidth, u32 boundheight, u32 width, u32 height, s32 xpos, s32 ypos)
|
||||
{
|
||||
u16* oam = (u16*)&GPU::OAM[Num ? 0x400 : 0];
|
||||
u16* attrib = &oam[num * 4];
|
||||
u16* rotparams = &oam[(((attrib[1] >> 9) & 0x1F) * 16) + 3];
|
||||
|
||||
u32 pixelattr = ((attrib[2] & 0x0C00) << 6) | 0xC0000;
|
||||
u32 tilenum = attrib[2] & 0x03FF;
|
||||
u32 spritemode = window ? 0 : ((attrib[0] >> 10) & 0x3);
|
||||
|
@ -2429,9 +2459,6 @@ void GPU2D::DrawSprite_Rotscale(u16* attrib, u16* rotparams, u32 boundwidth, u32
|
|||
if ((attrib[0] & 0x1000) && !window)
|
||||
{
|
||||
// apply Y mosaic
|
||||
ypos = OBJMosaicY - (attrib[0] & 0xFF);
|
||||
if (ypos < 0) ypos = 0;
|
||||
|
||||
pixelattr |= 0x100000;
|
||||
}
|
||||
|
||||
|
@ -2509,12 +2536,15 @@ void GPU2D::DrawSprite_Rotscale(u16* attrib, u16* rotparams, u32 boundwidth, u32
|
|||
if (color & 0x8000)
|
||||
{
|
||||
if (window) OBJWindow[xpos] = 1;
|
||||
else OBJLine[xpos] = color | pixelattr;
|
||||
else { OBJLine[xpos] = color | pixelattr; OBJIndex[xpos] = num; }
|
||||
}
|
||||
else if (!window)
|
||||
{
|
||||
if (OBJLine[xpos] == 0)
|
||||
{
|
||||
OBJLine[xpos] = pixelattr & 0x180000;
|
||||
OBJIndex[xpos] = num;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2563,12 +2593,15 @@ void GPU2D::DrawSprite_Rotscale(u16* attrib, u16* rotparams, u32 boundwidth, u32
|
|||
if (color)
|
||||
{
|
||||
if (window) OBJWindow[xpos] = 1;
|
||||
else OBJLine[xpos] = color | pixelattr;
|
||||
else { OBJLine[xpos] = color | pixelattr; OBJIndex[xpos] = num; }
|
||||
}
|
||||
else if (!window)
|
||||
{
|
||||
if (OBJLine[xpos] == 0)
|
||||
{
|
||||
OBJLine[xpos] = pixelattr & 0x180000;
|
||||
OBJIndex[xpos] = num;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2604,12 +2637,15 @@ void GPU2D::DrawSprite_Rotscale(u16* attrib, u16* rotparams, u32 boundwidth, u32
|
|||
if (color)
|
||||
{
|
||||
if (window) OBJWindow[xpos] = 1;
|
||||
else OBJLine[xpos] = color | pixelattr;
|
||||
else { OBJLine[xpos] = color | pixelattr; OBJIndex[xpos] = num; }
|
||||
}
|
||||
else if (!window)
|
||||
{
|
||||
if (OBJLine[xpos] == 0)
|
||||
{
|
||||
OBJLine[xpos] = pixelattr & 0x180000;
|
||||
OBJIndex[xpos] = num;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2623,8 +2659,11 @@ void GPU2D::DrawSprite_Rotscale(u16* attrib, u16* rotparams, u32 boundwidth, u32
|
|||
}
|
||||
|
||||
template<bool window>
|
||||
void GPU2D::DrawSprite_Normal(u16* attrib, u32 width, s32 xpos, s32 ypos)
|
||||
void GPU2D::DrawSprite_Normal(u32 num, u32 width, u32 height, s32 xpos, s32 ypos)
|
||||
{
|
||||
u16* oam = (u16*)&GPU::OAM[Num ? 0x400 : 0];
|
||||
u16* attrib = &oam[num * 4];
|
||||
|
||||
u32 pixelattr = ((attrib[2] & 0x0C00) << 6) | 0xC0000;
|
||||
u32 tilenum = attrib[2] & 0x03FF;
|
||||
u32 spritemode = window ? 0 : ((attrib[0] >> 10) & 0x3);
|
||||
|
@ -2634,12 +2673,13 @@ void GPU2D::DrawSprite_Normal(u16* attrib, u32 width, s32 xpos, s32 ypos)
|
|||
if ((attrib[0] & 0x1000) && !window)
|
||||
{
|
||||
// apply Y mosaic
|
||||
ypos = OBJMosaicY - (attrib[0] & 0xFF);
|
||||
if (ypos < 0) ypos = 0;
|
||||
|
||||
pixelattr |= 0x100000;
|
||||
}
|
||||
|
||||
// yflip
|
||||
if (attrib[1] & 0x2000)
|
||||
ypos = height-1 - ypos;
|
||||
|
||||
u32 xoff;
|
||||
u32 xend = width;
|
||||
if (xpos >= 0)
|
||||
|
@ -2719,12 +2759,15 @@ void GPU2D::DrawSprite_Normal(u16* attrib, u32 width, s32 xpos, s32 ypos)
|
|||
if (color & 0x8000)
|
||||
{
|
||||
if (window) OBJWindow[xpos] = 1;
|
||||
else OBJLine[xpos] = color | pixelattr;
|
||||
else { OBJLine[xpos] = color | pixelattr; OBJIndex[xpos] = num; }
|
||||
}
|
||||
else if (!window)
|
||||
{
|
||||
if (OBJLine[xpos] == 0)
|
||||
{
|
||||
OBJLine[xpos] = pixelattr & 0x180000;
|
||||
OBJIndex[xpos] = num;
|
||||
}
|
||||
}
|
||||
|
||||
xoff++;
|
||||
|
@ -2786,12 +2829,15 @@ void GPU2D::DrawSprite_Normal(u16* attrib, u32 width, s32 xpos, s32 ypos)
|
|||
if (color)
|
||||
{
|
||||
if (window) OBJWindow[xpos] = 1;
|
||||
else OBJLine[xpos] = color | pixelattr;
|
||||
else { OBJLine[xpos] = color | pixelattr; OBJIndex[xpos] = num; }
|
||||
}
|
||||
else if (!window)
|
||||
{
|
||||
if (OBJLine[xpos] == 0)
|
||||
{
|
||||
OBJLine[xpos] = pixelattr & 0x180000;
|
||||
OBJIndex[xpos] = num;
|
||||
}
|
||||
}
|
||||
|
||||
xoff++;
|
||||
|
@ -2847,12 +2893,15 @@ void GPU2D::DrawSprite_Normal(u16* attrib, u32 width, s32 xpos, s32 ypos)
|
|||
if (color)
|
||||
{
|
||||
if (window) OBJWindow[xpos] = 1;
|
||||
else OBJLine[xpos] = color | pixelattr;
|
||||
else { OBJLine[xpos] = color | pixelattr; OBJIndex[xpos] = num; }
|
||||
}
|
||||
else if (!window)
|
||||
{
|
||||
if (OBJLine[xpos] == 0)
|
||||
{
|
||||
OBJLine[xpos] = pixelattr & 0x180000;
|
||||
OBJIndex[xpos] = num;
|
||||
}
|
||||
}
|
||||
|
||||
xoff++;
|
||||
|
|
|
@ -78,6 +78,7 @@ private:
|
|||
u8 WindowMask[256] __attribute__((aligned (8)));
|
||||
u32 OBJLine[256] __attribute__((aligned (8)));
|
||||
u8 OBJWindow[256] __attribute__((aligned (8)));
|
||||
u8 OBJIndex[256] __attribute__((aligned (8)));
|
||||
|
||||
u32 NumSprites;
|
||||
|
||||
|
@ -156,8 +157,8 @@ private:
|
|||
|
||||
void ApplySpriteMosaicX();
|
||||
void InterleaveSprites(u32 prio);
|
||||
template<bool window> void DrawSprite_Rotscale(u16* attrib, u16* rotparams, u32 boundwidth, u32 boundheight, u32 width, u32 height, s32 xpos, s32 ypos);
|
||||
template<bool window> void DrawSprite_Normal(u16* attrib, u32 width, s32 xpos, s32 ypos);
|
||||
template<bool window> void DrawSprite_Rotscale(u32 num, u32 boundwidth, u32 boundheight, u32 width, u32 height, s32 xpos, s32 ypos);
|
||||
template<bool window> void DrawSprite_Normal(u32 num, u32 width, u32 height, s32 xpos, s32 ypos);
|
||||
|
||||
void DoCapture(u32 line, u32 width);
|
||||
|
||||
|
|
|
@ -807,7 +807,6 @@ void RenderSceneChunk(int y, int h)
|
|||
else
|
||||
glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ONE, GL_ONE);
|
||||
|
||||
UseRenderShader(flags | RenderFlag_Trans);
|
||||
glLineWidth(1.0);
|
||||
|
||||
if (NumOpaqueFinalPolys > -1)
|
||||
|
@ -843,6 +842,8 @@ void RenderSceneChunk(int y, int h)
|
|||
}
|
||||
else if (rp->PolyData->Translucent)
|
||||
{
|
||||
UseRenderShader(flags | RenderFlag_Trans);
|
||||
|
||||
// zorp
|
||||
glDepthFunc(GL_LESS);
|
||||
|
||||
|
|
|
@ -2662,6 +2662,45 @@ int main(int argc, char** argv)
|
|||
SDL_Quit();
|
||||
return 0;
|
||||
}
|
||||
if (!Platform::LocalFileExists("firmware.bin.bak"))
|
||||
{
|
||||
// verify the firmware
|
||||
//
|
||||
// there are dumps of an old hacked firmware floating around on the internet
|
||||
// and those are problematic
|
||||
// the hack predates WFC, and, due to this, any game that alters the WFC
|
||||
// access point data will brick that firmware due to it having critical
|
||||
// data in the same area. it has the same problem on hardware.
|
||||
//
|
||||
// but this should help stop users from reporting that issue over and over
|
||||
// again, when the issue is not from melonDS but from their firmware dump.
|
||||
//
|
||||
// I don't know about all the firmware hacks in existence, but the one I
|
||||
// looked at has 0x180 bytes from the header repeated at 0x3FC80, but
|
||||
// bytes 0x0C-0x14 are different.
|
||||
|
||||
FILE* f = Platform::OpenLocalFile("firmware.bin", "rb");
|
||||
u8 chk1[0x180], chk2[0x180];
|
||||
|
||||
fseek(f, 0, SEEK_SET);
|
||||
fread(chk1, 1, 0x180, f);
|
||||
fseek(f, -0x380, SEEK_END);
|
||||
fread(chk2, 1, 0x180, f);
|
||||
|
||||
memset(&chk1[0x0C], 0, 8);
|
||||
memset(&chk2[0x0C], 0, 8);
|
||||
|
||||
fclose(f);
|
||||
|
||||
if (!memcmp(chk1, chk2, 0x180))
|
||||
{
|
||||
uiMsgBoxError(NULL,
|
||||
"Problematic firmware dump",
|
||||
"You are using an old hacked firmware dump.\n"
|
||||
"Firmware boot will stop working if you run any game that alters WFC settings.\n\n"
|
||||
"Note that the issue is not from melonDS, it would also happen on an actual DS.");
|
||||
}
|
||||
}
|
||||
{
|
||||
FILE* f = Platform::OpenLocalFile("romlist.bin", "rb");
|
||||
if (f)
|
||||
|
|
Loading…
Reference in New Issue