Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/ARM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1154,13 +1154,16 @@ void ARMv4::DataRead32S(u32 addr, u32* val)

void ARMv4::DataWrite8(u32 addr, u8 val)
{
// decrease ARM7 write count if the write targets the main RAM, which is starving bus
if (NDS.ARM7BytesToWrite && (addr >> 24) == 0x02) NDS.DecreaseARM7BytesToWrite(1);
BusWrite8(addr, val);
DataRegion = addr;
DataCycles = NDS.ARM7MemTimings[addr >> 15][0];
}

void ARMv4::DataWrite16(u32 addr, u16 val)
{
if (NDS.ARM7BytesToWrite && (addr >> 24) == 0x02) NDS.DecreaseARM7BytesToWrite(2);
addr &= ~1;

BusWrite16(addr, val);
Expand All @@ -1170,6 +1173,7 @@ void ARMv4::DataWrite16(u32 addr, u16 val)

void ARMv4::DataWrite32(u32 addr, u32 val)
{
if (NDS.ARM7BytesToWrite && (addr >> 24) == 0x02) NDS.DecreaseARM7BytesToWrite(4);
addr &= ~3;

BusWrite32(addr, val);
Expand All @@ -1179,6 +1183,7 @@ void ARMv4::DataWrite32(u32 addr, u32 val)

void ARMv4::DataWrite32S(u32 addr, u32 val)
{
if (NDS.ARM7BytesToWrite && (addr >> 24) == 0x02) NDS.DecreaseARM7BytesToWrite(4);
addr &= ~3;

BusWrite32(addr, val);
Expand Down
7 changes: 7 additions & 0 deletions src/ARMInterpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,10 @@ void A_MRC(ARM* cpu)

void A_SVC(ARM* cpu)
{
// update ARM9 starvation status on a BIOS call
if (cpu->Num == 1)
cpu->NDS.UpdateARM9Starve((cpu->CurInstr >> 16) & 0xFF, cpu->R[1], cpu->R[2]);

u32 oldcpsr = cpu->CPSR;
cpu->CPSR &= ~0xBF;
cpu->CPSR |= 0x93;
Expand All @@ -278,6 +282,9 @@ void A_SVC(ARM* cpu)

void T_SVC(ARM* cpu)
{
if (cpu->Num == 1)
cpu->NDS.UpdateARM9Starve(cpu->CurInstr & 0xFF, cpu->R[1], cpu->R[2]);

u32 oldcpsr = cpu->CPSR;
cpu->CPSR &= ~0xBF;
cpu->CPSR |= 0x93;
Expand Down
48 changes: 48 additions & 0 deletions src/NDS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,8 @@ void NDS::Reset()
IPCFIFO9.Clear();
IPCFIFO7.Clear();

ARM7BytesToWrite = 0;

DivCnt = 0;
SqrtCnt = 0;

Expand Down Expand Up @@ -683,6 +685,7 @@ bool NDS::DoSavestate(Savestate* file)
file->Var16(&SqrtCnt);

file->Var32(&CPUStop);
file->Var32(&ARM7BytesToWrite);

for (int i = 0; i < 8; i++)
{
Expand Down Expand Up @@ -1002,6 +1005,11 @@ u32 NDS::RunFrame()
dsi.RunNDMAs(0);
}
}
else if (CPUStop & CPUStop_ARM9BusStarve)
{
// starved of main RAM by the ARM7, see UpdateARM9Starve()
ARM9Timestamp = ARM9Target;
}
else
{
ARM9.Execute<cpuMode>();
Expand Down Expand Up @@ -1092,6 +1100,46 @@ u32 NDS::RunFrame()
}
}

void NDS::UpdateARM9Starve(u32 swi, u32 dst, u32 cnt)
{
// Update the number of bytes that ARM7 will transfer to main RAM.
// DecreaseARM7BytesToWrite() will consumes it as the ARM7 writes;
// at zero the ARM9 is released.

// accept only CpuSet and CpuFastSet call
// see: https://problemkaputt.de/gbatek-bios-memory-copy.htm
if (swi != 0x0B && swi != 0x0C) return;

// destination must be in main RAM
if ((dst >> 24) != 0x02) return;

// bus starvation occurs only when ARM7 has higher priority
if (!(ExMemCnt[0] & (1<<15))) return;

u32 units = cnt & 0x1FFFFF;
u32 bytes = (swi == 0x0C || (cnt & (1<<26))) ? (units << 2) : (units << 1);

// The original intention of simulating bus starvation is for some problematic games,
// like DSi PictoChat, whose ARM7 fills a wide range of main RAM. Transfers below 4KB
// are too short for the starvation to matter and are ignored.
if (bytes < 0x1000) return;

ARM7BytesToWrite = bytes;
CPUStop |= CPUStop_ARM9BusStarve;
}

void NDS::DecreaseARM7BytesToWrite(u32 bytes)
{
if (bytes < ARM7BytesToWrite)
{
ARM7BytesToWrite -= bytes;
return;
}

ARM7BytesToWrite = 0;
CPUStop &= ~CPUStop_ARM9BusStarve;
}

void NDS::Reschedule(u64 target)
{
if (CurCPU == 0)
Expand Down
8 changes: 8 additions & 0 deletions src/NDS.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,8 @@ enum
CPUStop_NDMA9_3 = (1<<7),
CPUStop_DMA9 = 0xFFF,

CPUStop_ARM9BusStarve = (1<<14),

CPUStop_DMA7_0 = (1<<16),
CPUStop_DMA7_1 = (1<<17),
CPUStop_DMA7_2 = (1<<18),
Expand Down Expand Up @@ -289,6 +291,7 @@ class NDS
u16 PowerControl9;

u16 ExMemCnt[2];
u32 ARM7BytesToWrite;

protected:
// These BIOS arrays should be declared *before* the component objects (JIT, SPI, etc.)
Expand Down Expand Up @@ -443,6 +446,11 @@ class NDS
bool HaltInterrupted(u32 cpu) const;
void StopCPU(u32 cpu, u32 mask);
void ResumeCPU(u32 cpu, u32 mask);

// ARM9 starvation while the ARM7 has main RAM priority
void UpdateARM9Starve(u32 swi, u32 dst, u32 cnt);
void DecreaseARM7BytesToWrite(u32 bytes);

void GXFIFOStall();
void GXFIFOUnstall();

Expand Down
2 changes: 1 addition & 1 deletion src/Savestate.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
#include <stdio.h>
#include "types.h"

#define SAVESTATE_MAJOR 14
#define SAVESTATE_MAJOR 15
#define SAVESTATE_MINOR 0

// bitmask for the savestate config word
Expand Down
Loading