aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorStapleButter <thetotalworm@gmail.com>2018-11-04 23:21:58 +0100
committerStapleButter <thetotalworm@gmail.com>2018-11-04 23:21:58 +0100
commitb4165cc0a907906440608b2023babed7a7e1f14e (patch)
treebde137e476efe23767424a9eefc7c1a0853e6d90 /src
parentfb284f33ad6573be7a43bddb040c2573c67dba17 (diff)
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.
Diffstat (limited to 'src')
-rw-r--r--src/ARM.cpp31
-rw-r--r--src/ARM.h19
-rw-r--r--src/CP15.cpp12
-rw-r--r--src/CP15.h5
-rw-r--r--src/GPU3D_Soft.cpp22
-rw-r--r--src/NDS.cpp79
-rw-r--r--src/NDS.h11
7 files changed, 165 insertions, 14 deletions
diff --git a/src/ARM.cpp b/src/ARM.cpp
index 2368a1b..d71d0e1 100644
--- a/src/ARM.cpp
+++ b/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;
}
}
diff --git a/src/ARM.h b/src/ARM.h
index 92d47bb..b778be4 100644
--- a/src/ARM.h
+++ b/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
diff --git a/src/CP15.cpp b/src/CP15.cpp
index e3f0bae..229c560 100644
--- a/src/CP15.cpp
+++ b/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;
+}
+
}
diff --git a/src/CP15.h b/src/CP15.h
index 1b92191..a01034c 100644
--- a/src/CP15.h
+++ b/src/CP15.h
@@ -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
diff --git a/src/GPU3D_Soft.cpp b/src/GPU3D_Soft.cpp
index bb48c97..811d5f6 100644
--- a/src/GPU3D_Soft.cpp
+++ b/src/GPU3D_Soft.cpp
@@ -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;
diff --git a/src/NDS.cpp b/src/NDS.cpp
index 40f0c2d..77810ee 100644
--- a/src/NDS.cpp
+++ b/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;
+}
+
diff --git a/src/NDS.h b/src/NDS.h
index 1bf8508..c7913e9 100644
--- a/src/NDS.h
+++ b/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);