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:
StapleButter 2018-11-04 23:21:58 +01:00
parent fb284f33ad
commit b4165cc0a9
7 changed files with 165 additions and 14 deletions

View File

@ -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;
}
}

View File

@ -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

View File

@ -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;
}
}

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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);