aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/DMA.cpp20
-rw-r--r--src/DMA.h6
-rw-r--r--src/GPU.cpp22
-rw-r--r--src/GPU2D.cpp28
-rw-r--r--src/GPU2D.h4
-rw-r--r--src/NDS.cpp9
-rw-r--r--src/NDS.h1
7 files changed, 76 insertions, 14 deletions
diff --git a/src/DMA.cpp b/src/DMA.cpp
index 5a7ca1c..14fe791 100644
--- a/src/DMA.cpp
+++ b/src/DMA.cpp
@@ -20,7 +20,7 @@
#include "NDS.h"
#include "DMA.h"
#include "NDSCart.h"
-#include "GPU3D.h"
+#include "GPU.h"
// NOTES ON DMA SHIT
@@ -153,8 +153,8 @@ void DMA::WriteCnt(u32 val)
else if (StartMode == 0x07)
GPU3D::CheckFIFODMA();
- if (StartMode==0x04 || StartMode==0x06 || StartMode==0x13)
- printf("UNIMPLEMENTED ARM%d DMA%d START MODE %02X\n", CPU?7:9, Num, StartMode);
+ if (StartMode==0x06 || StartMode==0x13)
+ printf("UNIMPLEMENTED ARM%d DMA%d START MODE %02X, %08X->%08X\n", CPU?7:9, Num, StartMode, SrcAddr, DstAddr);
}
}
@@ -194,6 +194,20 @@ void DMA::Start()
return;
}
+ // special path for the display FIFO. another gross hack.
+ // the display FIFO seems to be more like a circular buffer that holds 16 pixels
+ // from which the display controller reads. DMA is triggered every 8 pixels to fill it
+ // as it is being read from. emulating it properly would be resource intensive.
+ // proper emulation would only matter if something is trying to feed the FIFO manually
+ // instead of using the DMA. which is probably never happening. the only thing I know of
+ // that even uses the display FIFO is the aging cart.
+ if (StartMode == 0x04)
+ {
+ GPU::GPU2D_A->FIFODMA(CurSrcAddr);
+ CurSrcAddr += 256*2;
+ return;
+ }
+
// TODO eventually: not stop if we're running code in ITCM
Running = true;
diff --git a/src/DMA.h b/src/DMA.h
index 59a7f03..1b8bbb2 100644
--- a/src/DMA.h
+++ b/src/DMA.h
@@ -40,6 +40,12 @@ public:
Start();
}
+ void StopIfNeeded(u32 mode)
+ {
+ if (mode == StartMode)
+ Cnt &= ~0x80000000;
+ }
+
u32 SrcAddr;
u32 DstAddr;
u32 Cnt;
diff --git a/src/GPU.cpp b/src/GPU.cpp
index aaef43f..5b9bf33 100644
--- a/src/GPU.cpp
+++ b/src/GPU.cpp
@@ -678,13 +678,23 @@ void StartScanline(u32 line)
else
DispStat[1] &= ~(1<<2);
+ if (line >= 2 && line < 194)
+ NDS::CheckDMAs(0, 0x03);
+ else if (line == 194)
+ NDS::StopDMAs(0, 0x03);
+
if (line < 192)
{
+ // fill a line from the display FIFO if needed.
+ // this isn't how the real thing works, but emulating it
+ // properly would be too much trouble given barely anything
+ // uses FIFO display
+ // (TODO, eventually: emulate it properly)
+ NDS::CheckDMAs(0, 0x04);
+
// draw
GPU2D_A->DrawScanline(line);
GPU2D_B->DrawScanline(line);
-
- //NDS::ScheduleEvent(LINE_CYCLES, StartScanline, line+1);
}
else if (line == 262)
{
@@ -701,6 +711,8 @@ void StartScanline(u32 line)
DispStat[0] |= (1<<0);
DispStat[1] |= (1<<0);
+ NDS::StopDMAs(0, 0x04);
+
NDS::CheckDMAs(0, 0x01);
NDS::CheckDMAs(1, 0x11);
@@ -711,14 +723,8 @@ void StartScanline(u32 line)
GPU2D_B->VBlank();
GPU3D::VBlank();
}
-
- //NDS::ScheduleEvent(LINE_CYCLES, StartScanline, line+1);
- //NDS::ScheduleEvent(NDS::Event_LCD, true, LINE_CYCLES, StartScanline, line+1);
}
- // checkme
- if (line == 0) NDS::CheckDMAs(0, 0x03);
-
NDS::ScheduleEvent(NDS::Event_LCD, true, HBLANK_CYCLES, StartHBlank, line);
}
diff --git a/src/GPU2D.cpp b/src/GPU2D.cpp
index cedfe1e..3717cf5 100644
--- a/src/GPU2D.cpp
+++ b/src/GPU2D.cpp
@@ -91,6 +91,8 @@ void GPU2D::Reset()
EVB = 0;
EVY = 0;
+ memset(DispFIFOBuffer, 0, 256*2);
+
CaptureCnt = 0;
MasterBrightness = 0;
@@ -337,9 +339,17 @@ void GPU2D::DrawScanline(u32 line)
}
break;
- case 3: // FIFO display
+ case 3: // FIFO display (grossly inaccurate)
{
- // TODO
+ for (int i = 0; i < 256; i++)
+ {
+ u16 color = DispFIFOBuffer[i];
+ u8 r = (color & 0x001F) << 1;
+ u8 g = (color & 0x03E0) >> 4;
+ u8 b = (color & 0x7C00) >> 9;
+
+ dst[i] = r | (g << 8) | (b << 16);
+ }
}
break;
}
@@ -445,7 +455,8 @@ void GPU2D::DoCapture(u32 line, u32 width, u32* src)
if (CaptureCnt & (1<<25))
{
- // TODO: FIFO mode
+ srcB = &DispFIFOBuffer[0];
+ srcBaddr = 0;
}
else
{
@@ -570,6 +581,17 @@ void GPU2D::DoCapture(u32 line, u32 width, u32* src)
}
}
+void GPU2D::FIFODMA(u32 addr)
+{
+ for (int i = 0; i < 256; i += 2)
+ {
+ u32 val = NDS::ARM9Read32(addr);
+ addr += 4;
+ DispFIFOBuffer[i] = val & 0xFFFF;
+ DispFIFOBuffer[i+1] = val >> 16;
+ }
+}
+
void GPU2D::BGExtPalDirty(u32 base)
{
diff --git a/src/GPU2D.h b/src/GPU2D.h
index 4136440..acbe967 100644
--- a/src/GPU2D.h
+++ b/src/GPU2D.h
@@ -45,10 +45,14 @@ public:
u16* GetBGExtPal(u32 slot, u32 pal);
u16* GetOBJExtPal(u32 pal);
+ void FIFODMA(u32 addr);
+
private:
u32 Num;
u32* Framebuffer;
+ u16 DispFIFOBuffer[256];
+
u32 DispCnt;
u16 BGCnt[4];
diff --git a/src/NDS.cpp b/src/NDS.cpp
index 3ab543e..d2fa59c 100644
--- a/src/NDS.cpp
+++ b/src/NDS.cpp
@@ -622,6 +622,15 @@ void CheckDMAs(u32 cpu, u32 mode)
DMAs[cpu+3]->StartIfNeeded(mode);
}
+void StopDMAs(u32 cpu, u32 mode)
+{
+ cpu <<= 2;
+ DMAs[cpu+0]->StopIfNeeded(mode);
+ DMAs[cpu+1]->StopIfNeeded(mode);
+ DMAs[cpu+2]->StopIfNeeded(mode);
+ DMAs[cpu+3]->StopIfNeeded(mode);
+}
+
diff --git a/src/NDS.h b/src/NDS.h
index 28f777e..9721c84 100644
--- a/src/NDS.h
+++ b/src/NDS.h
@@ -148,6 +148,7 @@ void StopCPU(u32 cpu, u32 mask);
void ResumeCPU(u32 cpu, u32 mask);
void CheckDMAs(u32 cpu, u32 mode);
+void StopDMAs(u32 cpu, u32 mode);
void RunTimingCriticalDevices(u32 cpu, s32 cycles);