diff options
author | StapleButter <thetotalworm@gmail.com> | 2018-11-04 23:21:58 +0100 |
---|---|---|
committer | StapleButter <thetotalworm@gmail.com> | 2018-11-04 23:21:58 +0100 |
commit | b4165cc0a907906440608b2023babed7a7e1f14e (patch) | |
tree | bde137e476efe23767424a9eefc7c1a0853e6d90 | |
parent | fb284f33ad6573be7a43bddb040c2573c67dba17 (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.
-rw-r--r-- | src/ARM.cpp | 31 | ||||
-rw-r--r-- | src/ARM.h | 19 | ||||
-rw-r--r-- | src/CP15.cpp | 12 | ||||
-rw-r--r-- | src/CP15.h | 5 | ||||
-rw-r--r-- | src/GPU3D_Soft.cpp | 22 | ||||
-rw-r--r-- | src/NDS.cpp | 79 | ||||
-rw-r--r-- | src/NDS.h | 11 |
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; } } @@ -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; +} + } @@ -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; +} + @@ -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); |