3D: keep the rasterizer from accidentally going out of bounds when given very flat X-major edge slopes.
this, by a fucking shitshow of butterfly effect, ends up fixing #234. technically, the rasterizer was going out of bounds, which, under certain circumstances, caused interpolation to shit itself and generate Z values that were out of range (but still ended up in the zbuffer). sometimes those values ended up negative, which caused these glitches when polygons had to be drawn over those. about fucking time.
This commit is contained in:
parent
fb284f33ad
commit
b4165cc0a9
31
src/ARM.cpp
31
src/ARM.cpp
|
@ -157,6 +157,8 @@ void ARM::Reset()
|
|||
|
||||
ExceptionBase = Num ? 0x00000000 : 0xFFFF0000;
|
||||
|
||||
CodeMem.Mem = NULL;
|
||||
|
||||
// zorp
|
||||
JumpTo(ExceptionBase);
|
||||
}
|
||||
|
@ -180,6 +182,24 @@ void ARM::DoSavestate(Savestate* file)
|
|||
file->VarArray(NextInstr, 2*sizeof(u32));
|
||||
|
||||
file->Var32(&ExceptionBase);
|
||||
|
||||
if (!file->Saving)
|
||||
SetupCodeMem(R[15]); // should fix it
|
||||
}
|
||||
|
||||
void ARM::SetupCodeMem(u32 addr)
|
||||
{
|
||||
if (!Num)
|
||||
{
|
||||
if (CP15::GetCodeMemRegion(addr, &CodeMem))
|
||||
return;
|
||||
|
||||
NDS::ARM9GetMemRegion(addr, false, &CodeMem);
|
||||
}
|
||||
else
|
||||
{
|
||||
NDS::ARM7GetMemRegion(addr, false, &CodeMem);
|
||||
}
|
||||
}
|
||||
|
||||
void ARM::JumpTo(u32 addr, bool restorecpsr)
|
||||
|
@ -196,20 +216,31 @@ void ARM::JumpTo(u32 addr, bool restorecpsr)
|
|||
//if (addr == 0x0201764C) printf("capture test %d: R1=%08X\n", R[6], R[1]);
|
||||
//if (addr == 0x020175D8) printf("capture test %d: res=%08X\n", R[6], R[0]);
|
||||
|
||||
u32 oldregion = R[15] >> 23;
|
||||
u32 newregion = addr >> 23;
|
||||
//if(!Num)printf("ARM%c branch from %08X to %08X. %03X->%03X\n", Num?'7':'9', R[15], addr, oldregion, newregion);
|
||||
if (addr & 0x1)
|
||||
{
|
||||
addr &= ~0x1;
|
||||
R[15] = addr+2;
|
||||
|
||||
if (newregion != oldregion) SetupCodeMem(addr);
|
||||
|
||||
NextInstr[0] = CodeRead16(addr);
|
||||
NextInstr[1] = CodeRead16(addr+2);
|
||||
|
||||
CPSR |= 0x20;
|
||||
}
|
||||
else
|
||||
{
|
||||
addr &= ~0x3;
|
||||
R[15] = addr+4;
|
||||
|
||||
if (newregion != oldregion) SetupCodeMem(addr);
|
||||
|
||||
NextInstr[0] = CodeRead32(addr);
|
||||
NextInstr[1] = CodeRead32(addr+4);
|
||||
|
||||
CPSR &= ~0x20;
|
||||
}
|
||||
}
|
||||
|
|
19
src/ARM.h
19
src/ARM.h
|
@ -93,11 +93,19 @@ public:
|
|||
|
||||
void TriggerIRQ();
|
||||
|
||||
void SetupCodeMem(u32 addr);
|
||||
|
||||
|
||||
u16 CodeRead16(u32 addr)
|
||||
{
|
||||
Cycles += Waitstates[0][(addr>>24)&0xF];
|
||||
|
||||
if (CodeMem.Mem) return *(u16*)&CodeMem.Mem[addr & CodeMem.Mask];
|
||||
|
||||
u16 val;
|
||||
// TODO eventually: on ARM9, THUMB opcodes are prefetched with 32bit reads
|
||||
// probably not worth going through the trouble. we can probably just simulate
|
||||
// the timing quirks resulting from this. or not.
|
||||
if (!Num)
|
||||
{
|
||||
if (!CP15::HandleCodeRead16(addr, &val))
|
||||
|
@ -106,12 +114,15 @@ public:
|
|||
else
|
||||
val = NDS::ARM7Read16(addr);
|
||||
|
||||
Cycles += Waitstates[0][(addr>>24)&0xF];
|
||||
return val;
|
||||
}
|
||||
|
||||
u32 CodeRead32(u32 addr)
|
||||
{
|
||||
Cycles += Waitstates[1][(addr>>24)&0xF];
|
||||
|
||||
if (CodeMem.Mem) return *(u32*)&CodeMem.Mem[addr & CodeMem.Mask];
|
||||
|
||||
u32 val;
|
||||
if (!Num)
|
||||
{
|
||||
|
@ -121,7 +132,6 @@ public:
|
|||
else
|
||||
val = NDS::ARM7Read32(addr);
|
||||
|
||||
Cycles += Waitstates[1][(addr>>24)&0xF];
|
||||
return val;
|
||||
}
|
||||
|
||||
|
@ -220,6 +230,7 @@ public:
|
|||
// waitstates:
|
||||
// 0=code16 1=code32 2=data16 3=data32
|
||||
// TODO eventually: nonsequential waitstates
|
||||
// TODO NOT MAKE THIS A FUCKING GROSS HACK!!!!!!
|
||||
s32 Waitstates[4][16];
|
||||
|
||||
s32 Cycles;
|
||||
|
@ -238,9 +249,9 @@ public:
|
|||
|
||||
u32 ExceptionBase;
|
||||
|
||||
static u32 ConditionTable[16];
|
||||
NDS::MemRegion CodeMem;
|
||||
|
||||
u32 debug;
|
||||
static u32 ConditionTable[16];
|
||||
};
|
||||
|
||||
namespace ARMInterpreter
|
||||
|
|
12
src/CP15.cpp
12
src/CP15.cpp
|
@ -316,4 +316,16 @@ bool HandleDataWrite32(u32 addr, u32 val, u32 forceuser)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool GetCodeMemRegion(u32 addr, NDS::MemRegion* region)
|
||||
{
|
||||
if (addr < ITCMSize)
|
||||
{
|
||||
region->Mem = ITCM;
|
||||
region->Mask = 0x7FFF;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
namespace CP15
|
||||
{
|
||||
|
||||
extern u8 ITCM[0x8000];
|
||||
extern u32 ITCMSize;
|
||||
|
||||
void Reset();
|
||||
|
||||
void DoSavestate(Savestate* file);
|
||||
|
@ -41,6 +44,8 @@ bool HandleDataWrite8(u32 addr, u8 val, u32 forceuser=0);
|
|||
bool HandleDataWrite16(u32 addr, u16 val, u32 forceuser=0);
|
||||
bool HandleDataWrite32(u32 addr, u32 val, u32 forceuser=0);
|
||||
|
||||
bool GetCodeMemRegion(u32 addr, NDS::MemRegion* region);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1213,7 +1213,9 @@ void RenderShadowMaskScanline(RendererPolygon* rp, s32 y)
|
|||
|
||||
// part 1: left edge
|
||||
edge = yedge | 0x1;
|
||||
xlimit = xstart+l_edgelen; if (xlimit > 256) xlimit = 256;
|
||||
xlimit = xstart+l_edgelen;
|
||||
if (xlimit > xend+1) xlimit = xend+1;
|
||||
if (xlimit > 256) xlimit = 256;
|
||||
|
||||
for (; x < xlimit; x++)
|
||||
{
|
||||
|
@ -1241,7 +1243,9 @@ void RenderShadowMaskScanline(RendererPolygon* rp, s32 y)
|
|||
|
||||
// part 2: polygon inside
|
||||
edge = yedge;
|
||||
xlimit = xend-r_edgelen+1; if (xlimit > 256) xlimit = 256;
|
||||
xlimit = xend-r_edgelen+1;
|
||||
if (xlimit > xend+1) xlimit = xend+1;
|
||||
if (xlimit > 256) xlimit = 256;
|
||||
if (wireframe && !edge) x = xlimit;
|
||||
else for (; x < xlimit; x++)
|
||||
{
|
||||
|
@ -1265,7 +1269,8 @@ void RenderShadowMaskScanline(RendererPolygon* rp, s32 y)
|
|||
|
||||
// part 3: right edge
|
||||
edge = yedge | 0x2;
|
||||
xlimit = xend+1; if (xlimit > 256) xlimit = 256;
|
||||
xlimit = xend+1;
|
||||
if (xlimit > 256) xlimit = 256;
|
||||
|
||||
for (; x < xlimit; x++)
|
||||
{
|
||||
|
@ -1436,7 +1441,9 @@ void RenderPolygonScanline(RendererPolygon* rp, s32 y)
|
|||
|
||||
// part 1: left edge
|
||||
edge = yedge | 0x1;
|
||||
xlimit = xstart+l_edgelen; if (xlimit > 256) xlimit = 256;
|
||||
xlimit = xstart+l_edgelen;
|
||||
if (xlimit > xend+1) xlimit = xend+1;
|
||||
if (xlimit > 256) xlimit = 256;
|
||||
if (l_edgecov & (1<<31))
|
||||
{
|
||||
xcov = (l_edgecov >> 12) & 0x3FF;
|
||||
|
@ -1535,7 +1542,9 @@ void RenderPolygonScanline(RendererPolygon* rp, s32 y)
|
|||
|
||||
// part 2: polygon inside
|
||||
edge = yedge;
|
||||
xlimit = xend-r_edgelen+1; if (xlimit > 256) xlimit = 256;
|
||||
xlimit = xend-r_edgelen+1;
|
||||
if (xlimit > xend+1) xlimit = xend+1;
|
||||
if (xlimit > 256) xlimit = 256;
|
||||
if (wireframe && !edge) x = xlimit;
|
||||
else for (; x < xlimit; x++)
|
||||
{
|
||||
|
@ -1603,7 +1612,8 @@ void RenderPolygonScanline(RendererPolygon* rp, s32 y)
|
|||
|
||||
// part 3: right edge
|
||||
edge = yedge | 0x2;
|
||||
xlimit = xend+1; if (xlimit > 256) xlimit = 256;
|
||||
xlimit = xend+1;
|
||||
if (xlimit > 256) xlimit = 256;
|
||||
if (r_edgecov & (1<<31))
|
||||
{
|
||||
xcov = (r_edgecov >> 12) & 0x3FF;
|
||||
|
|
79
src/NDS.cpp
79
src/NDS.cpp
|
@ -36,10 +36,6 @@
|
|||
namespace NDS
|
||||
{
|
||||
|
||||
// TODO LIST
|
||||
// * stick all the variables in a big structure?
|
||||
// would make it easier to deal with savestates
|
||||
|
||||
ARM* ARM9;
|
||||
ARM* ARM7;
|
||||
|
||||
|
@ -1350,6 +1346,36 @@ void ARM9Write32(u32 addr, u32 val)
|
|||
printf("unknown arm9 write32 %08X %08X | %08X\n", addr, val, ARM9->R[15]);
|
||||
}
|
||||
|
||||
bool ARM9GetMemRegion(u32 addr, bool write, MemRegion* region)
|
||||
{
|
||||
switch (addr & 0xFF000000)
|
||||
{
|
||||
case 0x02000000:
|
||||
region->Mem = MainRAM;
|
||||
region->Mask = MAIN_RAM_SIZE-1;
|
||||
return true;
|
||||
|
||||
case 0x03000000:
|
||||
if (SWRAM_ARM9)
|
||||
{
|
||||
region->Mem = SWRAM_ARM9;
|
||||
region->Mask = SWRAM_ARM9Mask;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if ((addr & 0xFFFFF000) == 0xFFFF0000 && !write)
|
||||
{
|
||||
region->Mem = ARM9BIOS;
|
||||
region->Mask = 0xFFF;
|
||||
return true;
|
||||
}
|
||||
|
||||
region->Mem = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
u8 ARM7Read8(u32 addr)
|
||||
|
@ -1571,6 +1597,51 @@ void ARM7Write32(u32 addr, u32 val)
|
|||
//printf("unknown arm7 write32 %08X %08X @ %08X\n", addr, val, ARM7->R[15]);
|
||||
}
|
||||
|
||||
bool ARM7GetMemRegion(u32 addr, bool write, MemRegion* region)
|
||||
{
|
||||
switch (addr & 0xFF800000)
|
||||
{
|
||||
case 0x02000000:
|
||||
case 0x02800000:
|
||||
region->Mem = MainRAM;
|
||||
region->Mask = MAIN_RAM_SIZE-1;
|
||||
return true;
|
||||
|
||||
case 0x03000000:
|
||||
// note on this, and why we can only cover it in one particular case:
|
||||
// it is typical for games to map all shared WRAM to the ARM7
|
||||
// then access all the WRAM as one contiguous block starting at 0x037F8000
|
||||
// this case needs a bit of a hack to cover
|
||||
// it's not really worth bothering anyway
|
||||
if (!SWRAM_ARM7)
|
||||
{
|
||||
region->Mem = ARM7WRAM;
|
||||
region->Mask = 0xFFFF;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x03800000:
|
||||
region->Mem = ARM7WRAM;
|
||||
region->Mask = 0xFFFF;
|
||||
return true;
|
||||
}
|
||||
|
||||
// BIOS. ARM7 PC has to be within range.
|
||||
if (addr < 0x00004000 && !write)
|
||||
{
|
||||
if (ARM7->R[15] < 0x4000 && (addr >= ARM7BIOSProt || ARM7->R[15] < ARM7BIOSProt))
|
||||
{
|
||||
region->Mem = ARM7BIOS;
|
||||
region->Mask = 0x3FFF;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
region->Mem = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
11
src/NDS.h
11
src/NDS.h
|
@ -87,6 +87,13 @@ typedef struct
|
|||
|
||||
} Timer;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8* Mem;
|
||||
u32 Mask;
|
||||
|
||||
} MemRegion;
|
||||
|
||||
// hax
|
||||
extern u32 IME[2];
|
||||
extern u32 IE[2];
|
||||
|
@ -157,6 +164,8 @@ void ARM9Write8(u32 addr, u8 val);
|
|||
void ARM9Write16(u32 addr, u16 val);
|
||||
void ARM9Write32(u32 addr, u32 val);
|
||||
|
||||
bool ARM9GetMemRegion(u32 addr, bool write, MemRegion* region);
|
||||
|
||||
u8 ARM7Read8(u32 addr);
|
||||
u16 ARM7Read16(u32 addr);
|
||||
u32 ARM7Read32(u32 addr);
|
||||
|
@ -164,6 +173,8 @@ void ARM7Write8(u32 addr, u8 val);
|
|||
void ARM7Write16(u32 addr, u16 val);
|
||||
void ARM7Write32(u32 addr, u32 val);
|
||||
|
||||
bool ARM7GetMemRegion(u32 addr, bool write, MemRegion* region);
|
||||
|
||||
u8 ARM9IORead8(u32 addr);
|
||||
u16 ARM9IORead16(u32 addr);
|
||||
u32 ARM9IORead32(u32 addr);
|
||||
|
|
Loading…
Reference in New Issue