mirror of
https://github.com/melonDS-emu/melonDS.git
synced 2025-07-23 14:19:55 -06:00
tremble upon the NDMA implementation
that doesn't do much beyond getting stuck
This commit is contained in:
301
src/DSi_NDMA.cpp
301
src/DSi_NDMA.cpp
@ -15,3 +15,304 @@
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with melonDS. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "NDS.h"
|
||||
#include "DSi.h"
|
||||
#include "DSi_NDMA.h"
|
||||
#include "GPU.h"
|
||||
|
||||
|
||||
|
||||
DSi_NDMA::DSi_NDMA(u32 cpu, u32 num)
|
||||
{
|
||||
CPU = cpu;
|
||||
Num = num;
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
DSi_NDMA::~DSi_NDMA()
|
||||
{
|
||||
}
|
||||
|
||||
void DSi_NDMA::Reset()
|
||||
{
|
||||
SrcAddr = 0;
|
||||
DstAddr = 0;
|
||||
TotalLength = 0;
|
||||
BlockLength = 0;
|
||||
SubblockTimer = 0;
|
||||
FillData = 0;
|
||||
Cnt = 0;
|
||||
|
||||
StartMode = 0;
|
||||
CurSrcAddr = 0;
|
||||
CurDstAddr = 0;
|
||||
SubblockLength = 0;
|
||||
RemCount = 0;
|
||||
IterCount = 0;
|
||||
TotalRemCount = 0;
|
||||
SrcAddrInc = 0;
|
||||
DstAddrInc = 0;
|
||||
|
||||
Running = false;
|
||||
InProgress = false;
|
||||
}
|
||||
|
||||
void DSi_NDMA::DoSavestate(Savestate* file)
|
||||
{
|
||||
// TODO!
|
||||
}
|
||||
|
||||
void DSi_NDMA::WriteCnt(u32 val)
|
||||
{
|
||||
u32 oldcnt = Cnt;
|
||||
Cnt = val;
|
||||
|
||||
if ((!(oldcnt & 0x80000000)) && (val & 0x80000000)) // checkme
|
||||
{
|
||||
CurSrcAddr = SrcAddr;
|
||||
CurDstAddr = DstAddr;
|
||||
TotalRemCount = TotalLength;
|
||||
|
||||
switch ((Cnt >> 10) & 0x3)
|
||||
{
|
||||
case 0: DstAddrInc = 1; break;
|
||||
case 1: DstAddrInc = -1; break;
|
||||
case 2: DstAddrInc = 0; break;
|
||||
case 3: DstAddrInc = 1; printf("BAD NDMA DST INC MODE 3\n"); break;
|
||||
}
|
||||
|
||||
switch ((Cnt >> 13) & 0x3)
|
||||
{
|
||||
case 0: SrcAddrInc = 1; break;
|
||||
case 1: SrcAddrInc = -1; break;
|
||||
case 2: SrcAddrInc = 0; break;
|
||||
case 3: SrcAddrInc = 0; break; // fill mode
|
||||
}
|
||||
|
||||
StartMode = (Cnt >> 24) & 0x1F;
|
||||
if (StartMode > 0x10) StartMode = 0x10;
|
||||
if (CPU == 1) StartMode |= 0x20;
|
||||
|
||||
if ((StartMode & 0x1F) == 0x10)
|
||||
Start();
|
||||
|
||||
if (StartMode != 0x10 && StartMode != 0x30)
|
||||
printf("UNIMPLEMENTED ARM%d NDMA%d START MODE %02X, %08X->%08X\n", CPU?7:9, Num, StartMode, SrcAddr, DstAddr);
|
||||
}
|
||||
}
|
||||
|
||||
void DSi_NDMA::Start()
|
||||
{
|
||||
if (Running) return;
|
||||
|
||||
if (!InProgress)
|
||||
{
|
||||
RemCount = BlockLength;
|
||||
if (!RemCount)
|
||||
RemCount = 0x1000000;
|
||||
}
|
||||
|
||||
// TODO: how does GXFIFO DMA work with all the block shito?
|
||||
IterCount = RemCount;
|
||||
|
||||
if (IterCount > TotalRemCount)
|
||||
IterCount = TotalRemCount;
|
||||
|
||||
if (Cnt & (1<<12)) CurDstAddr = DstAddr;
|
||||
if (Cnt & (1<<15)) CurSrcAddr = SrcAddr;
|
||||
|
||||
printf("ARM%d NDMA%d %08X %02X %08X->%08X %d bytes\n", CPU?7:9, Num, Cnt, StartMode, CurSrcAddr, CurDstAddr, RemCount*4);
|
||||
|
||||
//IsGXFIFODMA = (CPU == 0 && (CurSrcAddr>>24) == 0x02 && CurDstAddr == 0x04000400 && DstAddrInc == 0);
|
||||
|
||||
// TODO eventually: not stop if we're running code in ITCM
|
||||
|
||||
if (SubblockTimer & 0xFFFF)
|
||||
printf("TODO! NDMA SUBBLOCK TIMER: %08X\n", SubblockTimer);
|
||||
|
||||
if (NDS::DMAsRunning(CPU))
|
||||
Running = 1;
|
||||
else
|
||||
Running = 2;
|
||||
|
||||
InProgress = true;
|
||||
NDS::StopCPU(CPU, 1<<(Num+4));
|
||||
}
|
||||
|
||||
void DSi_NDMA::Run()
|
||||
{
|
||||
if (!Running) return;
|
||||
if (CPU == 0) return Run9();
|
||||
else return Run7();
|
||||
}
|
||||
|
||||
void DSi_NDMA::Run9()
|
||||
{
|
||||
if (NDS::ARM9Timestamp >= NDS::ARM9Target) return;
|
||||
|
||||
Executing = true;
|
||||
|
||||
// add NS penalty for first accesses in burst
|
||||
bool burststart = (Running == 2);
|
||||
Running = 1;
|
||||
|
||||
s32 unitcycles;
|
||||
//s32 lastcycles = cycles;
|
||||
|
||||
bool dofill = ((Cnt >> 13) & 0x3) == 3;
|
||||
|
||||
if ((CurSrcAddr >> 24) == 0x02 && (CurDstAddr >> 24) == 0x02)
|
||||
{
|
||||
unitcycles = NDS::ARM9MemTimings[CurSrcAddr >> 14][2] + NDS::ARM9MemTimings[CurDstAddr >> 14][2];
|
||||
}
|
||||
else
|
||||
{
|
||||
unitcycles = NDS::ARM9MemTimings[CurSrcAddr >> 14][3] + NDS::ARM9MemTimings[CurDstAddr >> 14][3];
|
||||
if ((CurSrcAddr >> 24) == (CurDstAddr >> 24))
|
||||
unitcycles++;
|
||||
else if ((CurSrcAddr >> 24) == 0x02)
|
||||
unitcycles--;
|
||||
|
||||
/*if (burststart)
|
||||
{
|
||||
cycles -= 2;
|
||||
cycles -= (NDS::ARM9MemTimings[CurSrcAddr >> 14][2] + NDS::ARM9MemTimings[CurDstAddr >> 14][2]);
|
||||
cycles += unitcycles;
|
||||
}*/
|
||||
}
|
||||
|
||||
while (IterCount > 0 && !Stall)
|
||||
{
|
||||
NDS::ARM9Timestamp += (unitcycles << NDS::ARM9ClockShift);
|
||||
|
||||
if (dofill)
|
||||
DSi::ARM9Write32(CurDstAddr, FillData);
|
||||
else
|
||||
DSi::ARM9Write32(CurDstAddr, DSi::ARM9Read32(CurSrcAddr));
|
||||
|
||||
CurSrcAddr += SrcAddrInc<<2;
|
||||
CurDstAddr += DstAddrInc<<2;
|
||||
IterCount--;
|
||||
RemCount--;
|
||||
TotalRemCount--;
|
||||
|
||||
if (NDS::ARM9Timestamp >= NDS::ARM9Target) break;
|
||||
}
|
||||
|
||||
Executing = false;
|
||||
Stall = false;
|
||||
|
||||
if (RemCount)
|
||||
{
|
||||
if (IterCount == 0)
|
||||
{
|
||||
Running = 0;
|
||||
NDS::ResumeCPU(0, 1<<(Num+4));
|
||||
|
||||
//if (StartMode == 0x07)
|
||||
// GPU3D::CheckFIFODMA();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ((StartMode & 0x1F) == 0x10) // CHECKME
|
||||
Cnt &= ~(1<<31);
|
||||
else if (!(Cnt & (1<<29)))
|
||||
{
|
||||
if (TotalRemCount == 0)
|
||||
Cnt &= ~(1<<31);
|
||||
}
|
||||
|
||||
if (Cnt & (1<<30))
|
||||
NDS::SetIRQ(0, NDS::IRQ_DSi_NDMA0 + Num);
|
||||
|
||||
Running = 0;
|
||||
InProgress = false;
|
||||
NDS::ResumeCPU(0, 1<<(Num+4));
|
||||
}
|
||||
|
||||
void DSi_NDMA::Run7()
|
||||
{
|
||||
if (NDS::ARM7Timestamp >= NDS::ARM7Target) return;
|
||||
|
||||
Executing = true;
|
||||
|
||||
// add NS penalty for first accesses in burst
|
||||
bool burststart = (Running == 2);
|
||||
Running = 1;
|
||||
|
||||
s32 unitcycles;
|
||||
//s32 lastcycles = cycles;
|
||||
|
||||
bool dofill = ((Cnt >> 13) & 0x3) == 3;
|
||||
|
||||
if ((CurSrcAddr >> 24) == 0x02 && (CurDstAddr >> 24) == 0x02)
|
||||
{
|
||||
unitcycles = NDS::ARM7MemTimings[CurSrcAddr >> 15][2] + NDS::ARM7MemTimings[CurDstAddr >> 15][2];
|
||||
}
|
||||
else
|
||||
{
|
||||
unitcycles = NDS::ARM7MemTimings[CurSrcAddr >> 15][3] + NDS::ARM7MemTimings[CurDstAddr >> 15][3];
|
||||
if ((CurSrcAddr >> 23) == (CurDstAddr >> 23))
|
||||
unitcycles++;
|
||||
else if ((CurSrcAddr >> 24) == 0x02)
|
||||
unitcycles--;
|
||||
|
||||
/*if (burststart)
|
||||
{
|
||||
cycles -= 2;
|
||||
cycles -= (NDS::ARM7MemTimings[CurSrcAddr >> 15][2] + NDS::ARM7MemTimings[CurDstAddr >> 15][2]);
|
||||
cycles += unitcycles;
|
||||
}*/
|
||||
}
|
||||
|
||||
while (IterCount > 0 && !Stall)
|
||||
{
|
||||
NDS::ARM7Timestamp += unitcycles;
|
||||
|
||||
if (dofill)
|
||||
DSi::ARM7Write32(CurDstAddr, FillData);
|
||||
else
|
||||
DSi::ARM7Write32(CurDstAddr, DSi::ARM7Read32(CurSrcAddr));
|
||||
|
||||
CurSrcAddr += SrcAddrInc<<2;
|
||||
CurDstAddr += DstAddrInc<<2;
|
||||
IterCount--;
|
||||
RemCount--;
|
||||
|
||||
if (NDS::ARM7Timestamp >= NDS::ARM7Target) break;
|
||||
}
|
||||
|
||||
Executing = false;
|
||||
Stall = false;
|
||||
|
||||
if (RemCount)
|
||||
{
|
||||
if (IterCount == 0)
|
||||
{
|
||||
Running = 0;
|
||||
NDS::ResumeCPU(1, 1<<(Num+4));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ((StartMode & 0x1F) == 0x10) // CHECKME
|
||||
Cnt &= ~(1<<31);
|
||||
else if (!(Cnt & (1<<29)))
|
||||
{
|
||||
if (TotalRemCount == 0)
|
||||
Cnt &= ~(1<<31);
|
||||
}
|
||||
|
||||
if (Cnt & (1<<30))
|
||||
NDS::SetIRQ(1, NDS::IRQ_DSi_NDMA0 + Num);
|
||||
|
||||
Running = 0;
|
||||
InProgress = false;
|
||||
NDS::ResumeCPU(1, 1<<(Num+4));
|
||||
}
|
||||
|
Reference in New Issue
Block a user