emulate DMA timings.

keeps games from overflowing the GXFIFO... when they aren't fucking dumb.
This commit is contained in:
StapleButter
2017-02-17 05:33:37 +01:00
parent abd2cb444b
commit cca0a71d81
7 changed files with 176 additions and 34 deletions

4
ARM.h
View File

@ -125,7 +125,7 @@ public:
else else
val = NDS::ARM7Read8(addr); val = NDS::ARM7Read8(addr);
Cycles += Waitstates[3][(addr>>24)&0xF]; Cycles += Waitstates[2][(addr>>24)&0xF];
return val; return val;
} }
@ -171,7 +171,7 @@ public:
else else
NDS::ARM7Write8(addr, val); NDS::ARM7Write8(addr, val);
Cycles += Waitstates[3][(addr>>24)&0xF]; Cycles += Waitstates[2][(addr>>24)&0xF];
} }
void DataWrite16(u32 addr, u16 val, u32 forceuser=0) void DataWrite16(u32 addr, u16 val, u32 forceuser=0)

118
DMA.cpp
View File

@ -34,6 +34,66 @@ DMA::DMA(u32 cpu, u32 num)
CPU = cpu; CPU = cpu;
Num = num; Num = num;
if (cpu == 0)
CountMask = 0x001FFFFF;
else
CountMask = (num==3 ? 0x0000FFFF : 0x00003FFF);
// TODO: merge with the one in ARM.cpp, somewhere
for (int i = 0; i < 16; i++)
{
Waitstates[0][i] = 1;
Waitstates[1][i] = 1;
}
if (!num)
{
// ARM9
// note: 33MHz cycles
Waitstates[0][0x2] = 1;
Waitstates[0][0x3] = 1;
Waitstates[0][0x4] = 1;
Waitstates[0][0x5] = 1;
Waitstates[0][0x6] = 1;
Waitstates[0][0x7] = 1;
Waitstates[0][0x8] = 6;
Waitstates[0][0x9] = 6;
Waitstates[0][0xA] = 10;
Waitstates[0][0xF] = 1;
Waitstates[1][0x2] = 2;
Waitstates[1][0x3] = 1;
Waitstates[1][0x4] = 1;
Waitstates[1][0x5] = 2;
Waitstates[1][0x6] = 2;
Waitstates[1][0x7] = 1;
Waitstates[1][0x8] = 12;
Waitstates[1][0x9] = 12;
Waitstates[1][0xA] = 10;
Waitstates[1][0xF] = 1;
}
else
{
// ARM7
Waitstates[0][0x0] = 1;
Waitstates[0][0x2] = 1;
Waitstates[0][0x3] = 1;
Waitstates[0][0x4] = 1;
Waitstates[0][0x6] = 1;
Waitstates[0][0x8] = 6;
Waitstates[0][0x9] = 6;
Waitstates[0][0xA] = 10;
Waitstates[1][0x0] = 1;
Waitstates[1][0x2] = 2;
Waitstates[1][0x3] = 1;
Waitstates[1][0x4] = 1;
Waitstates[1][0x6] = 2;
Waitstates[1][0x8] = 12;
Waitstates[1][0x9] = 12;
Waitstates[1][0xA] = 10;
}
Reset(); Reset();
} }
@ -51,8 +111,11 @@ void DMA::Reset()
CurSrcAddr = 0; CurSrcAddr = 0;
CurDstAddr = 0; CurDstAddr = 0;
RemCount = 0; RemCount = 0;
IterCount = 0;
SrcAddrInc = 0; SrcAddrInc = 0;
DstAddrInc = 0; DstAddrInc = 0;
Running = false;
} }
void DMA::WriteCnt(u32 val) void DMA::WriteCnt(u32 val)
@ -90,16 +153,16 @@ void DMA::WriteCnt(u32 val)
Start(); Start();
else if (StartMode == 0x07) else if (StartMode == 0x07)
GPU3D::CheckFIFODMA(); GPU3D::CheckFIFODMA();
//else
// printf("SPECIAL ARM%d DMA%d START MODE %02X\n", CPU?7:9, Num, StartMode);
if ((StartMode&7)!=0x00 && (StartMode&7)!=0x1 && StartMode!=2 && StartMode!=0x05 && StartMode!=0x12 && StartMode!=0x07) if ((StartMode&7)!=0x00 && (StartMode&7)!=0x1 && StartMode!=2 && StartMode!=0x05 && StartMode!=0x12 && StartMode!=0x07)
printf("UNIMPLEMENTED ARM%d DMA%d START MODE %02X\n", CPU?7:9, Num, StartMode); printf("UNIMPLEMENTED ARM%d DMA%d START MODE %02X\n", CPU?7:9, Num, StartMode);
//if (StartMode==2)printf("HBLANK DMA %08X -> %08X\n", SrcAddr, DstAddr);
} }
} }
void DMA::Start() void DMA::Start()
{ {
if (Running) return;
u32 countmask; u32 countmask;
if (CPU == 0) if (CPU == 0)
countmask = 0x001FFFFF; countmask = 0x001FFFFF;
@ -110,6 +173,11 @@ void DMA::Start()
if (!RemCount) if (!RemCount)
RemCount = countmask+1; RemCount = countmask+1;
if (StartMode == 0x07 && RemCount > 112)
IterCount = 112;
else
IterCount = RemCount;
if ((Cnt & 0x00600000) == 0x00600000) if ((Cnt & 0x00600000) == 0x00600000)
CurDstAddr = DstAddr; CurDstAddr = DstAddr;
@ -126,24 +194,33 @@ void DMA::Start()
NDS::TriggerIRQ(CPU, NDS::IRQ_DMA0 + Num); NDS::TriggerIRQ(CPU, NDS::IRQ_DMA0 + Num);
return; return;
} }
//if (StartMode == 0x07)printf("GXFIFO DMA %08X %08X\n", Cnt, CurSrcAddr);
u32 num = RemCount;
if (StartMode == 0x07 && num > 112)
num = 112;
// TODO: NOT MAKE THE DMA INSTANT!! // TODO eventually: not stop if we're running code in ITCM
Running = true;
NDS::StopCPU(CPU, true);
}
s32 DMA::Run(s32 cycles)
{
if (!Running)
return cycles;
u32 zorp = IterCount;
if (!(Cnt & 0x04000000)) if (!(Cnt & 0x04000000))
{ {
u16 (*readfn)(u32) = CPU ? NDS::ARM7Read16 : NDS::ARM9Read16; u16 (*readfn)(u32) = CPU ? NDS::ARM7Read16 : NDS::ARM9Read16;
void (*writefn)(u32,u16) = CPU ? NDS::ARM7Write16 : NDS::ARM9Write16; void (*writefn)(u32,u16) = CPU ? NDS::ARM7Write16 : NDS::ARM9Write16;
while (num > 0) while (IterCount > 0 && cycles > 0)
{ {
writefn(CurDstAddr, readfn(CurSrcAddr)); writefn(CurDstAddr, readfn(CurSrcAddr));
cycles -= (Waitstates[0][(CurSrcAddr >> 24) & 0xF] + Waitstates[0][(CurDstAddr >> 24) & 0xF]);
CurSrcAddr += SrcAddrInc<<1; CurSrcAddr += SrcAddrInc<<1;
CurDstAddr += DstAddrInc<<1; CurDstAddr += DstAddrInc<<1;
num--; IterCount--;
RemCount--; RemCount--;
} }
} }
@ -152,22 +229,30 @@ void DMA::Start()
u32 (*readfn)(u32) = CPU ? NDS::ARM7Read32 : NDS::ARM9Read32; u32 (*readfn)(u32) = CPU ? NDS::ARM7Read32 : NDS::ARM9Read32;
void (*writefn)(u32,u32) = CPU ? NDS::ARM7Write32 : NDS::ARM9Write32; void (*writefn)(u32,u32) = CPU ? NDS::ARM7Write32 : NDS::ARM9Write32;
while (num > 0) while (IterCount > 0 && cycles > 0)
{ {
writefn(CurDstAddr, readfn(CurSrcAddr)); writefn(CurDstAddr, readfn(CurSrcAddr));
cycles -= (Waitstates[1][(CurSrcAddr >> 24) & 0xF] + Waitstates[1][(CurDstAddr >> 24) & 0xF]);
CurSrcAddr += SrcAddrInc<<2; CurSrcAddr += SrcAddrInc<<2;
CurDstAddr += DstAddrInc<<2; CurDstAddr += DstAddrInc<<2;
num--; IterCount--;
RemCount--; RemCount--;
} }
} }
if (RemCount) if (RemCount)
{ {
Cnt &= ~countmask; Cnt &= ~CountMask;
Cnt |= RemCount; Cnt |= RemCount;
return;
if (IterCount == 0)
{
Running = false;
NDS::StopCPU(CPU, false);
}
return cycles;
} }
if (!(Cnt & 0x02000000)) if (!(Cnt & 0x02000000))
@ -175,4 +260,9 @@ void DMA::Start()
if (Cnt & 0x40000000) if (Cnt & 0x40000000)
NDS::TriggerIRQ(CPU, NDS::IRQ_DMA0 + Num); NDS::TriggerIRQ(CPU, NDS::IRQ_DMA0 + Num);
Running = false;
NDS::StopCPU(CPU, false);
return cycles - 2;
} }

8
DMA.h
View File

@ -32,6 +32,8 @@ public:
void WriteCnt(u32 val); void WriteCnt(u32 val);
void Start(); void Start();
s32 Run(s32 cycles);
void StartIfNeeded(u32 mode) void StartIfNeeded(u32 mode)
{ {
if ((mode == StartMode) && (Cnt & 0x80000000)) if ((mode == StartMode) && (Cnt & 0x80000000))
@ -45,12 +47,18 @@ public:
private: private:
u32 CPU, Num; u32 CPU, Num;
s32 Waitstates[2][16];
u32 StartMode; u32 StartMode;
u32 CurSrcAddr; u32 CurSrcAddr;
u32 CurDstAddr; u32 CurDstAddr;
u32 RemCount; u32 RemCount;
u32 IterCount;
u32 SrcAddrInc; u32 SrcAddrInc;
u32 DstAddrInc; u32 DstAddrInc;
u32 CountMask;
bool Running;
}; };
#endif #endif

View File

@ -841,6 +841,8 @@ void SubmitVertex()
int logflag = 0;
void CmdFIFOWrite(CmdFIFOEntry& entry) void CmdFIFOWrite(CmdFIFOEntry& entry)
{ {
if (CmdFIFO->IsEmpty() && !CmdPIPE->IsFull()) if (CmdFIFO->IsEmpty() && !CmdPIPE->IsFull())
@ -852,7 +854,8 @@ void CmdFIFOWrite(CmdFIFOEntry& entry)
{ {
if (CmdFIFO->IsFull()) if (CmdFIFO->IsFull())
{ {
printf("!!! GX FIFO FULL\n"); if (!logflag) printf("!!! GX FIFO FULL\n");
logflag = 1;
//NDS::debug(0); //NDS::debug(0);
return; return;
} }
@ -876,6 +879,8 @@ CmdFIFOEntry CmdFIFORead()
CheckFIFOIRQ(); CheckFIFOIRQ();
} }
logflag = 0;
return ret; return ret;
} }

58
NDS.cpp
View File

@ -54,6 +54,8 @@ s32 ARM7Offset;
SchedEvent SchedList[Event_MAX]; SchedEvent SchedList[Event_MAX];
u32 SchedListMask; u32 SchedListMask;
u32 CPUStop;
u8 ARM9BIOS[0x1000]; u8 ARM9BIOS[0x1000];
u8 ARM7BIOS[0x4000]; u8 ARM7BIOS[0x4000];
@ -278,6 +280,8 @@ void Reset()
ARM7->Reset(); ARM7->Reset();
CP15::Reset(); CP15::Reset();
CPUStop = 0;
memset(Timers, 0, 8*sizeof(Timer)); memset(Timers, 0, 8*sizeof(Timer));
for (i = 0; i < 8; i++) DMAs[i]->Reset(); for (i = 0; i < 8; i++) DMAs[i]->Reset();
@ -307,7 +311,7 @@ void Reset()
// test // test
//LoadROM(); //LoadROM();
//LoadFirmware(); //LoadFirmware();
if (NDSCart::LoadROM("rom/nsmb.nds")) if (NDSCart::LoadROM("rom/raving.nds"))
Running = true; // hax Running = true; // hax
} }
@ -364,17 +368,45 @@ void RunFrame()
while (Running && framecycles>0) while (Running && framecycles>0)
{ {
CalcIterationCycles(); s32 ndscyclestorun;
ARM9->CyclesToRun = CurIterationCycles << 1;
ARM9->Execute();
s32 ndscyclestorun = ARM9->Cycles >> 1;
s32 ndscycles = 0; s32 ndscycles = 0;
ARM7->CyclesToRun = ndscyclestorun - ARM7Offset; CalcIterationCycles();
ARM7->Execute();
ARM7Offset = ARM7->Cycles - ARM7->CyclesToRun; if (CPUStop & 0x1)
{
s32 cycles = CurIterationCycles;
cycles = DMAs[0]->Run(cycles);
if (cycles > 0) cycles = DMAs[1]->Run(cycles);
if (cycles > 0) cycles = DMAs[2]->Run(cycles);
if (cycles > 0) cycles = DMAs[3]->Run(cycles);
ndscyclestorun = CurIterationCycles - cycles;
// TODO: run other timing critical shit, like timers
GPU3D::Run(ndscyclestorun);
}
else
{
ARM9->CyclesToRun = CurIterationCycles << 1;
ARM9->Execute();
ndscyclestorun = ARM9->Cycles >> 1;
}
if (CPUStop & 0x2)
{
s32 cycles = ndscyclestorun - ARM7Offset;
cycles = DMAs[4]->Run(cycles);
if (cycles > 0) cycles = DMAs[5]->Run(cycles);
if (cycles > 0) cycles = DMAs[6]->Run(cycles);
if (cycles > 0) cycles = DMAs[7]->Run(cycles);
ARM7Offset = cycles;
}
else
{
ARM7->CyclesToRun = ndscyclestorun - ARM7Offset;
ARM7->Execute();
ARM7Offset = ARM7->Cycles - ARM7->CyclesToRun;
}
RunSystem(ndscyclestorun); RunSystem(ndscyclestorun);
//GPU3D::Run(ndscyclestorun); //GPU3D::Run(ndscyclestorun);
@ -520,6 +552,12 @@ bool HaltInterrupted(u32 cpu)
return false; return false;
} }
void StopCPU(u32 cpu, bool stop)
{
if (stop) CPUStop |= (1<<cpu);
else CPUStop &= ~(1<<cpu);
}
void CheckDMAs(u32 cpu, u32 mode) void CheckDMAs(u32 cpu, u32 mode)

1
NDS.h
View File

@ -142,6 +142,7 @@ void MapSharedWRAM(u8 val);
void TriggerIRQ(u32 cpu, u32 irq); void TriggerIRQ(u32 cpu, u32 irq);
bool HaltInterrupted(u32 cpu); bool HaltInterrupted(u32 cpu);
void StopCPU(u32 cpu, bool stop);
void CheckDMAs(u32 cpu, u32 mode); void CheckDMAs(u32 cpu, u32 mode);

View File

@ -5,12 +5,12 @@
"NDS.h" "NDS.h"
"GPU.h" "GPU.h"
1486822548 c:\documents\sources\melonds\nds.h 1487303037 c:\documents\sources\melonds\nds.h
"types.h" "types.h"
1481161027 c:\documents\sources\melonds\types.h 1481161027 c:\documents\sources\melonds\types.h
1487299879 source:c:\documents\sources\melonds\nds.cpp 1487304040 source:c:\documents\sources\melonds\nds.cpp
<stdio.h> <stdio.h>
<string.h> <string.h>
"NDS.h" "NDS.h"
@ -31,7 +31,7 @@
"ARMInterpreter.h" "ARMInterpreter.h"
"GPU3D.h" "GPU3D.h"
1486261220 c:\documents\sources\melonds\arm.h 1487302172 c:\documents\sources\melonds\arm.h
"types.h" "types.h"
"NDS.h" "NDS.h"
"CP15.h" "CP15.h"
@ -109,14 +109,14 @@
1486511075 c:\documents\sources\melonds\fifo.h 1486511075 c:\documents\sources\melonds\fifo.h
"types.h" "types.h"
1486823366 source:c:\documents\sources\melonds\dma.cpp 1487305720 source:c:\documents\sources\melonds\dma.cpp
<stdio.h> <stdio.h>
"NDS.h" "NDS.h"
"DMA.h" "DMA.h"
"NDSCart.h" "NDSCart.h"
"GPU3D.h" "GPU3D.h"
1484698068 c:\documents\sources\melonds\dma.h 1487305393 c:\documents\sources\melonds\dma.h
"types.h" "types.h"
1487102235 source:c:\documents\sources\melonds\gpu.cpp 1487102235 source:c:\documents\sources\melonds\gpu.cpp
@ -148,14 +148,14 @@
1487287868 c:\documents\sources\melonds\gpu3d.h 1487287868 c:\documents\sources\melonds\gpu3d.h
1487299939 source:c:\documents\sources\melonds\gpu3d.cpp 1487305740 source:c:\documents\sources\melonds\gpu3d.cpp
<stdio.h> <stdio.h>
<string.h> <string.h>
"NDS.h" "NDS.h"
"GPU.h" "GPU.h"
"FIFO.h" "FIFO.h"
1487300098 source:c:\documents\sources\melonds\gpu3d_soft.cpp 1487300658 source:c:\documents\sources\melonds\gpu3d_soft.cpp
<stdio.h> <stdio.h>
<string.h> <string.h>
"NDS.h" "NDS.h"