implement some obscure DMA types

This commit is contained in:
StapleButter 2017-03-20 22:18:35 +01:00
parent a56bf5c76c
commit 2150240cbd
7 changed files with 76 additions and 14 deletions

View File

@ -20,7 +20,7 @@
#include "NDS.h" #include "NDS.h"
#include "DMA.h" #include "DMA.h"
#include "NDSCart.h" #include "NDSCart.h"
#include "GPU3D.h" #include "GPU.h"
// NOTES ON DMA SHIT // NOTES ON DMA SHIT
@ -153,8 +153,8 @@ void DMA::WriteCnt(u32 val)
else if (StartMode == 0x07) else if (StartMode == 0x07)
GPU3D::CheckFIFODMA(); GPU3D::CheckFIFODMA();
if (StartMode==0x04 || StartMode==0x06 || StartMode==0x13) if (StartMode==0x06 || StartMode==0x13)
printf("UNIMPLEMENTED ARM%d DMA%d START MODE %02X\n", CPU?7:9, Num, StartMode); 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; 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 // TODO eventually: not stop if we're running code in ITCM
Running = true; Running = true;

View File

@ -40,6 +40,12 @@ public:
Start(); Start();
} }
void StopIfNeeded(u32 mode)
{
if (mode == StartMode)
Cnt &= ~0x80000000;
}
u32 SrcAddr; u32 SrcAddr;
u32 DstAddr; u32 DstAddr;
u32 Cnt; u32 Cnt;

View File

@ -678,13 +678,23 @@ void StartScanline(u32 line)
else else
DispStat[1] &= ~(1<<2); DispStat[1] &= ~(1<<2);
if (line >= 2 && line < 194)
NDS::CheckDMAs(0, 0x03);
else if (line == 194)
NDS::StopDMAs(0, 0x03);
if (line < 192) 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 // draw
GPU2D_A->DrawScanline(line); GPU2D_A->DrawScanline(line);
GPU2D_B->DrawScanline(line); GPU2D_B->DrawScanline(line);
//NDS::ScheduleEvent(LINE_CYCLES, StartScanline, line+1);
} }
else if (line == 262) else if (line == 262)
{ {
@ -701,6 +711,8 @@ void StartScanline(u32 line)
DispStat[0] |= (1<<0); DispStat[0] |= (1<<0);
DispStat[1] |= (1<<0); DispStat[1] |= (1<<0);
NDS::StopDMAs(0, 0x04);
NDS::CheckDMAs(0, 0x01); NDS::CheckDMAs(0, 0x01);
NDS::CheckDMAs(1, 0x11); NDS::CheckDMAs(1, 0x11);
@ -711,14 +723,8 @@ void StartScanline(u32 line)
GPU2D_B->VBlank(); GPU2D_B->VBlank();
GPU3D::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); NDS::ScheduleEvent(NDS::Event_LCD, true, HBLANK_CYCLES, StartHBlank, line);
} }

View File

@ -91,6 +91,8 @@ void GPU2D::Reset()
EVB = 0; EVB = 0;
EVY = 0; EVY = 0;
memset(DispFIFOBuffer, 0, 256*2);
CaptureCnt = 0; CaptureCnt = 0;
MasterBrightness = 0; MasterBrightness = 0;
@ -337,9 +339,17 @@ void GPU2D::DrawScanline(u32 line)
} }
break; 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; break;
} }
@ -445,7 +455,8 @@ void GPU2D::DoCapture(u32 line, u32 width, u32* src)
if (CaptureCnt & (1<<25)) if (CaptureCnt & (1<<25))
{ {
// TODO: FIFO mode srcB = &DispFIFOBuffer[0];
srcBaddr = 0;
} }
else 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) void GPU2D::BGExtPalDirty(u32 base)
{ {

View File

@ -45,10 +45,14 @@ public:
u16* GetBGExtPal(u32 slot, u32 pal); u16* GetBGExtPal(u32 slot, u32 pal);
u16* GetOBJExtPal(u32 pal); u16* GetOBJExtPal(u32 pal);
void FIFODMA(u32 addr);
private: private:
u32 Num; u32 Num;
u32* Framebuffer; u32* Framebuffer;
u16 DispFIFOBuffer[256];
u32 DispCnt; u32 DispCnt;
u16 BGCnt[4]; u16 BGCnt[4];

View File

@ -622,6 +622,15 @@ void CheckDMAs(u32 cpu, u32 mode)
DMAs[cpu+3]->StartIfNeeded(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);
}

View File

@ -148,6 +148,7 @@ void StopCPU(u32 cpu, u32 mask);
void ResumeCPU(u32 cpu, u32 mask); void ResumeCPU(u32 cpu, u32 mask);
void CheckDMAs(u32 cpu, u32 mode); void CheckDMAs(u32 cpu, u32 mode);
void StopDMAs(u32 cpu, u32 mode);
void RunTimingCriticalDevices(u32 cpu, s32 cycles); void RunTimingCriticalDevices(u32 cpu, s32 cycles);