aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStapleButter <thetotalworm@gmail.com>2018-12-18 17:04:42 +0100
committerStapleButter <thetotalworm@gmail.com>2018-12-18 17:04:42 +0100
commitdd30b417b817024d48b4e14a23a2b19370e8ff97 (patch)
treeefa6fe0f4a535148826af98dedfd7b538245a6f8
parent1b64e871157314def6e82a476ba390d6f341f391 (diff)
implement proper support for POWCNT1.
fixes #260
-rw-r--r--src/GPU.cpp19
-rw-r--r--src/GPU.h2
-rw-r--r--src/GPU2D.cpp22
-rw-r--r--src/GPU2D.h2
-rw-r--r--src/GPU3D.cpp107
-rw-r--r--src/GPU3D.h2
-rw-r--r--src/GPU3D_Soft.cpp3
-rw-r--r--src/NDS.cpp27
8 files changed, 137 insertions, 47 deletions
diff --git a/src/GPU.cpp b/src/GPU.cpp
index aba97a5..ba04c84 100644
--- a/src/GPU.cpp
+++ b/src/GPU.cpp
@@ -650,9 +650,23 @@ void MapVRAM_I(u32 bank, u8 cnt)
}
-void DisplaySwap(u32 val)
+void SetPowerCnt(u32 val)
{
- if (val)
+ // POWCNT1 effects:
+ // * bit0: asplodes hardware??? not tested.
+ // * bit1: disables engine A palette and OAM (zero-filled) (TODO: affects mem timings???)
+ // * bit2: disables rendering engine, resets its internal state (polygons and registers)
+ // * bit3: disables geometry engine
+ // * bit9: disables engine B palette, OAM and rendering (screen turns white)
+ // * bit15: screen swap
+
+ if (!(val & (1<<0))) printf("!!! CLEARING POWCNT BIT0. DANGER\n");
+
+ GPU2D_A->SetEnabled(val & (1<<1));
+ GPU2D_B->SetEnabled(val & (1<<9));
+ GPU3D::SetEnabled(val & (1<<3), val & (1<<2));
+
+ if (val & (1<<15))
{
GPU2D_A->SetFramebuffer(&Framebuffer[256*0]);
GPU2D_B->SetFramebuffer(&Framebuffer[256*192]);
@@ -838,6 +852,7 @@ void SetVCount(u16 val)
// VCount write is delayed until the next scanline
// TODO: how does the 3D engine react to VCount writes while it's rendering?
+ // 3D engine seems to give up on the current frame in that situation, repeating the last two scanlines
// TODO: also check the various DMA types that can be involved
NextVCount = val;
diff --git a/src/GPU.h b/src/GPU.h
index 2ef33d9..6f5733d 100644
--- a/src/GPU.h
+++ b/src/GPU.h
@@ -387,7 +387,7 @@ T ReadVRAM_TexPal(u32 addr)
}
-void DisplaySwap(u32 val);
+void SetPowerCnt(u32 val);
void StartFrame();
void FinishFrame(u32 lines);
diff --git a/src/GPU2D.cpp b/src/GPU2D.cpp
index 4951404..f7e834d 100644
--- a/src/GPU2D.cpp
+++ b/src/GPU2D.cpp
@@ -273,6 +273,8 @@ u32 GPU2D::Read32(u32 addr)
void GPU2D::Write8(u32 addr, u8 val)
{
+ if (!Enabled) return;
+
switch (addr & 0x00000FFF)
{
case 0x000: DispCnt = (DispCnt & 0xFFFFFF00) | val; return;
@@ -353,6 +355,8 @@ void GPU2D::Write8(u32 addr, u8 val)
void GPU2D::Write16(u32 addr, u16 val)
{
+ if (!Enabled) return;
+
switch (addr & 0x00000FFF)
{
case 0x000: DispCnt = (DispCnt & 0xFFFF0000) | val; return;
@@ -482,6 +486,8 @@ void GPU2D::Write16(u32 addr, u16 val)
void GPU2D::Write32(u32 addr, u32 val)
{
+ if (!Enabled) return;
+
switch (addr & 0x00000FFF)
{
case 0x000:
@@ -542,19 +548,21 @@ void GPU2D::DrawScanline(u32 line)
line = GPU::VCount;
+ bool forceblank = false;
+
// scanlines that end up outside of the GPU drawing range
// (as a result of writing to VCount) are filled white
- if (line > 192)
- {
- for (int i = 0; i < 256; i++)
- dst[i] = 0xFFFFFFFF;
+ if (line > 192) forceblank = true;
- return;
- }
+ // GPU B can be completely disabled by POWCNT1
+ // oddly that's not the case for GPU A
+ if (Num && !Enabled) forceblank = true;
// forced blank
// (checkme: are there still things that can run under this mode? likely not)
- if (DispCnt & (1<<7))
+ if (DispCnt & (1<<7)) forceblank = true;
+
+ if (forceblank)
{
for (int i = 0; i < 256; i++)
dst[i] = 0xFFFFFFFF;
diff --git a/src/GPU2D.h b/src/GPU2D.h
index 5a1192e..1776680 100644
--- a/src/GPU2D.h
+++ b/src/GPU2D.h
@@ -29,6 +29,7 @@ public:
void DoSavestate(Savestate* file);
+ void SetEnabled(bool enable) { Enabled = enable; }
void SetFramebuffer(u32* buf);
u8 Read8(u32 addr);
@@ -64,6 +65,7 @@ public:
private:
u32 Num;
+ bool Enabled;
u32* Framebuffer;
u16 DispFIFO[16];
diff --git a/src/GPU3D.cpp b/src/GPU3D.cpp
index bc1ab1b..3b69577 100644
--- a/src/GPU3D.cpp
+++ b/src/GPU3D.cpp
@@ -152,6 +152,9 @@ FIFO<CmdFIFOEntry>* CmdStallQueue;
u32 NumCommands, CurCommand, ParamCount, TotalParams;
+bool GeometryEnabled;
+bool RenderingEnabled;
+
u32 DispCnt;
u8 AlphaRefVal, AlphaRef;
@@ -285,6 +288,25 @@ void DeInit()
delete CmdStallQueue;
}
+void ResetRenderingState()
+{
+ RenderNumPolygons = 0;
+
+ RenderDispCnt = 0;
+ RenderAlphaRef = 0;
+
+ memset(RenderEdgeTable, 0, 8*2);
+ memset(RenderToonTable, 0, 32*2);
+
+ RenderFogColor = 0;
+ RenderFogOffset = 0;
+ RenderFogShift = 0;
+ memset(RenderFogDensityTable, 0, 34);
+
+ RenderClearAttr1 = 0x3F000000;
+ RenderClearAttr2 = 0x00007FFF;
+}
+
void Reset()
{
CmdFIFO->Clear();
@@ -356,6 +378,7 @@ void Reset()
FlushRequest = 0;
FlushAttributes = 0;
+ ResetRenderingState();
SoftRenderer::Reset();
}
@@ -556,6 +579,16 @@ void DoSavestate(Savestate* file)
+void SetEnabled(bool geometry, bool rendering)
+{
+ GeometryEnabled = geometry;
+ RenderingEnabled = rendering;
+
+ if (!rendering) ResetRenderingState();
+}
+
+
+
void MatrixLoadIdentity(s32* m)
{
m[0] = 0x1000; m[1] = 0; m[2] = 0; m[3] = 0;
@@ -2213,6 +2246,8 @@ void FinishWork(s32 cycles)
void Run(s32 cycles)
{
+ if (!GeometryEnabled)
+ return;
if (FlushRequest)
return;
if (CmdPIPE->IsEmpty() && !(GXStat & (1<<27)))
@@ -2281,46 +2316,49 @@ bool YSort(Polygon* a, Polygon* b)
void VBlank()
{
- if (FlushRequest)
+ if (GeometryEnabled && FlushRequest)
{
- if (NumPolygons)
+ if (RenderingEnabled)
{
- // separate translucent polygons from opaque ones
-
- u32 io = 0, it = NumOpaquePolygons;
- for (u32 i = 0; i < NumPolygons; i++)
+ if (NumPolygons)
{
- Polygon* poly = &CurPolygonRAM[i];
- if (poly->Translucent)
- RenderPolygonRAM[it++] = poly;
- else
- RenderPolygonRAM[io++] = poly;
- }
+ // separate translucent polygons from opaque ones
+
+ u32 io = 0, it = NumOpaquePolygons;
+ for (u32 i = 0; i < NumPolygons; i++)
+ {
+ Polygon* poly = &CurPolygonRAM[i];
+ if (poly->Translucent)
+ RenderPolygonRAM[it++] = poly;
+ else
+ RenderPolygonRAM[io++] = poly;
+ }
- // apply Y-sorting
+ // apply Y-sorting
- std::stable_sort(RenderPolygonRAM.begin(),
- RenderPolygonRAM.begin() + ((FlushAttributes & 0x1) ? NumOpaquePolygons : NumPolygons),
- YSort);
- }
+ std::stable_sort(RenderPolygonRAM.begin(),
+ RenderPolygonRAM.begin() + ((FlushAttributes & 0x1) ? NumOpaquePolygons : NumPolygons),
+ YSort);
+ }
- RenderNumPolygons = NumPolygons;
+ RenderNumPolygons = NumPolygons;
- RenderDispCnt = DispCnt;
- RenderAlphaRef = AlphaRef;
+ RenderDispCnt = DispCnt;
+ RenderAlphaRef = AlphaRef;
- memcpy(RenderEdgeTable, EdgeTable, 8*2);
- memcpy(RenderToonTable, ToonTable, 32*2);
+ memcpy(RenderEdgeTable, EdgeTable, 8*2);
+ memcpy(RenderToonTable, ToonTable, 32*2);
- RenderFogColor = FogColor;
- RenderFogOffset = FogOffset * 0x200;
- RenderFogShift = (RenderDispCnt >> 8) & 0xF;
- RenderFogDensityTable[0] = FogDensityTable[0];
- memcpy(&RenderFogDensityTable[1], FogDensityTable, 32);
- RenderFogDensityTable[33] = FogDensityTable[31];
+ RenderFogColor = FogColor;
+ RenderFogOffset = FogOffset * 0x200;
+ RenderFogShift = (RenderDispCnt >> 8) & 0xF;
+ RenderFogDensityTable[0] = FogDensityTable[0];
+ memcpy(&RenderFogDensityTable[1], FogDensityTable, 32);
+ RenderFogDensityTable[33] = FogDensityTable[31];
- RenderClearAttr1 = ClearAttr1;
- RenderClearAttr2 = ClearAttr2;
+ RenderClearAttr1 = ClearAttr1;
+ RenderClearAttr2 = ClearAttr2;
+ }
CurRAMBank = CurRAMBank?0:1;
CurVertexRAM = &VertexRAM[CurRAMBank ? 6144 : 0];
@@ -2515,6 +2553,9 @@ u32 Read32(u32 addr)
void Write8(u32 addr, u8 val)
{
+ if (!RenderingEnabled && addr >= 0x04000320 && addr < 0x04000400) return;
+ if (!GeometryEnabled && addr >= 0x04000400 && addr < 0x04000700) return;
+
switch (addr)
{
case 0x04000340:
@@ -2550,6 +2591,9 @@ void Write8(u32 addr, u8 val)
void Write16(u32 addr, u16 val)
{
+ if (!RenderingEnabled && addr >= 0x04000320 && addr < 0x04000400) return;
+ if (!GeometryEnabled && addr >= 0x04000400 && addr < 0x04000700) return;
+
switch (addr)
{
case 0x04000060:
@@ -2629,6 +2673,9 @@ void Write16(u32 addr, u16 val)
void Write32(u32 addr, u32 val)
{
+ if (!RenderingEnabled && addr >= 0x04000320 && addr < 0x04000400) return;
+ if (!GeometryEnabled && addr >= 0x04000400 && addr < 0x04000700) return;
+
switch (addr)
{
case 0x04000060:
diff --git a/src/GPU3D.h b/src/GPU3D.h
index b74e421..d510d30 100644
--- a/src/GPU3D.h
+++ b/src/GPU3D.h
@@ -88,6 +88,8 @@ void Reset();
void DoSavestate(Savestate* file);
+void SetEnabled(bool geometry, bool rendering);
+
void ExecuteCommand();
s32 CyclesToRunFor();
diff --git a/src/GPU3D_Soft.cpp b/src/GPU3D_Soft.cpp
index daf5cdd..923348a 100644
--- a/src/GPU3D_Soft.cpp
+++ b/src/GPU3D_Soft.cpp
@@ -56,6 +56,8 @@ u32 AttrBuffer[BufferSize * 2];
u8 StencilBuffer[256*2];
bool PrevIsShadowMask;
+bool Enabled;
+
// threading
void* RenderThread;
@@ -137,6 +139,7 @@ void Reset()
}
+
// Notes on the interpolator:
//
// This is a theory on how the DS hardware interpolates values. It matches hardware output
diff --git a/src/NDS.cpp b/src/NDS.cpp
index 07273d7..aa8b1d3 100644
--- a/src/NDS.cpp
+++ b/src/NDS.cpp
@@ -363,7 +363,7 @@ void SetupDirectBoot()
PostFlag7 = 0x01;
PowerControl9 = 0x820F;
- GPU::DisplaySwap(PowerControl9);
+ GPU::SetPowerCnt(PowerControl9);
// checkme
RCnt = 0x8000;
@@ -678,8 +678,6 @@ bool DoSavestate(Savestate* file)
if (!file->Saving)
{
- GPU::DisplaySwap(PowerControl9>>15);
-
InitTimings();
SetGBASlotTimings();
@@ -698,6 +696,11 @@ bool DoSavestate(Savestate* file)
RTC::DoSavestate(file);
Wifi::DoSavestate(file);
+ if (!file->Saving)
+ {
+ GPU::SetPowerCnt(PowerControl9);
+ }
+
return true;
}
@@ -1618,6 +1621,7 @@ u8 ARM9Read8(u32 addr)
return ARM9IORead8(addr);
case 0x05000000:
+ if (!(PowerControl9 & ((addr & 0x400) ? (1<<9) : (1<<1)))) return 0;
return *(u8*)&GPU::Palette[addr & 0x7FF];
case 0x06000000:
@@ -1631,6 +1635,7 @@ u8 ARM9Read8(u32 addr)
}
case 0x07000000:
+ if (!(PowerControl9 & ((addr & 0x400) ? (1<<9) : (1<<1)))) return 0;
return *(u8*)&GPU::OAM[addr & 0x7FF];
case 0x08000000:
@@ -1677,6 +1682,7 @@ u16 ARM9Read16(u32 addr)
return ARM9IORead16(addr);
case 0x05000000:
+ if (!(PowerControl9 & ((addr & 0x400) ? (1<<9) : (1<<1)))) return 0;
return *(u16*)&GPU::Palette[addr & 0x7FF];
case 0x06000000:
@@ -1690,6 +1696,7 @@ u16 ARM9Read16(u32 addr)
}
case 0x07000000:
+ if (!(PowerControl9 & ((addr & 0x400) ? (1<<9) : (1<<1)))) return 0;
return *(u16*)&GPU::OAM[addr & 0x7FF];
case 0x08000000:
@@ -1736,6 +1743,7 @@ u32 ARM9Read32(u32 addr)
return ARM9IORead32(addr);
case 0x05000000:
+ if (!(PowerControl9 & ((addr & 0x400) ? (1<<9) : (1<<1)))) return 0;
return *(u32*)&GPU::Palette[addr & 0x7FF];
case 0x06000000:
@@ -1749,6 +1757,7 @@ u32 ARM9Read32(u32 addr)
}
case 0x07000000:
+ if (!(PowerControl9 & ((addr & 0x400) ? (1<<9) : (1<<1)))) return 0;
return *(u32*)&GPU::OAM[addr & 0x7FF];
case 0x08000000:
@@ -1818,6 +1827,7 @@ void ARM9Write16(u32 addr, u16 val)
return;
case 0x05000000:
+ if (!(PowerControl9 & ((addr & 0x400) ? (1<<9) : (1<<1)))) return;
*(u16*)&GPU::Palette[addr & 0x7FF] = val;
return;
@@ -1832,6 +1842,7 @@ void ARM9Write16(u32 addr, u16 val)
}
case 0x07000000:
+ if (!(PowerControl9 & ((addr & 0x400) ? (1<<9) : (1<<1)))) return;
*(u16*)&GPU::OAM[addr & 0x7FF] = val;
return;
}
@@ -1859,6 +1870,7 @@ void ARM9Write32(u32 addr, u32 val)
return;
case 0x05000000:
+ if (!(PowerControl9 & ((addr & 0x400) ? (1<<9) : (1<<1)))) return;
*(u32*)&GPU::Palette[addr & 0x7FF] = val;
return;
@@ -1873,6 +1885,7 @@ void ARM9Write32(u32 addr, u32 val)
}
case 0x07000000:
+ if (!(PowerControl9 & ((addr & 0x400) ? (1<<9) : (1<<1)))) return;
*(u32*)&GPU::OAM[addr & 0x7FF] = val;
return;
}
@@ -2809,8 +2822,8 @@ void ARM9IOWrite16(u32 addr, u16 val)
return;
case 0x04000304:
- PowerControl9 = val;
- GPU::DisplaySwap(PowerControl9>>15);
+ PowerControl9 = val & 0x820F;
+ GPU::SetPowerCnt(PowerControl9);
return;
}
@@ -2962,8 +2975,8 @@ void ARM9IOWrite32(u32 addr, u32 val)
case 0x040002BC: SqrtVal[1] = val; StartSqrt(); return;
case 0x04000304:
- PowerControl9 = val & 0xFFFF;
- GPU::DisplaySwap(PowerControl9>>15);
+ PowerControl9 = val & 0x820F;
+ GPU::SetPowerCnt(PowerControl9);
return;
}