Do ARAM DMA less often, and in larger chunks. hopefully it adds some speed, but probably only a tiny amount.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@4865 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
Shawn Hoffman 2010-01-17 07:20:15 +00:00
parent 59e7c19380
commit 4927e5607e
2 changed files with 84 additions and 102 deletions

View File

@ -82,8 +82,8 @@ union UARAMCount
u32 Hex; u32 Hex;
struct struct
{ {
unsigned count : 31; u32 count : 31;
unsigned dir : 1; u32 dir : 1; // 0: MRAM -> ARAM 1: ARAM -> MRAM
}; };
}; };
@ -94,21 +94,21 @@ union UDSPControl
u16 Hex; u16 Hex;
struct struct
{ {
unsigned DSPReset : 1; // Write 1 to reset and waits for 0 u16 DSPReset : 1; // Write 1 to reset and waits for 0
unsigned DSPAssertInt : 1; u16 DSPAssertInt : 1;
unsigned DSPHalt : 1; u16 DSPHalt : 1;
unsigned AID : 1; u16 AID : 1;
unsigned AID_mask : 1; u16 AID_mask : 1;
unsigned ARAM : 1; u16 ARAM : 1;
unsigned ARAM_mask : 1; u16 ARAM_mask : 1;
unsigned DSP : 1; u16 DSP : 1;
unsigned DSP_mask : 1; u16 DSP_mask : 1;
unsigned ARAM_DMAState : 1; // DSPGetDMAStatus() uses this flag u16 ARAM_DMAState : 1; // DSPGetDMAStatus() uses this flag
unsigned unk3 : 1; u16 unk3 : 1;
unsigned DSPInit : 1; // DSPInit() writes to this flag (1 as long as dsp PC is in IROM?) u16 DSPInit : 1; // DSPInit() writes to this flag (1 as long as dsp PC is in IROM?)
unsigned pad : 4; u16 pad : 4;
}; };
}; };
@ -128,8 +128,8 @@ union UAudioDMAControl
u16 Hex; u16 Hex;
struct struct
{ {
unsigned NumBlocks : 15; u16 NumBlocks : 15;
unsigned Enable : 1; u16 Enable : 1;
}; };
UAudioDMAControl(u16 _Hex = 0) : Hex(_Hex) UAudioDMAControl(u16 _Hex = 0) : Hex(_Hex)
@ -153,21 +153,18 @@ struct AudioDMA
} }
}; };
// ARDMA // ARAM_DMA
struct ARDMA struct ARAM_DMA
{ {
u32 MMAddr; u32 MMAddr;
u32 ARAddr; u32 ARAddr;
UARAMCount Cnt; UARAMCount Cnt;
bool CntValid[2];
ARDMA() ARAM_DMA()
{ {
MMAddr = 0; MMAddr = 0;
ARAddr = 0; ARAddr = 0;
Cnt.Hex = 0; Cnt.Hex = 0;
CntValid[0] = false;
CntValid[1] = false;
} }
}; };
@ -192,7 +189,7 @@ struct ARAMInfo
static ARAMInfo g_ARAM; static ARAMInfo g_ARAM;
static DSPState g_dspState; static DSPState g_dspState;
static AudioDMA g_audioDMA; static AudioDMA g_audioDMA;
static ARDMA g_arDMA; static ARAM_DMA g_arDMA;
static u16 g_AR_SIZE; static u16 g_AR_SIZE;
static u16 g_AR_MODE; static u16 g_AR_MODE;
static u16 g_AR_REFRESH; static u16 g_AR_REFRESH;
@ -214,7 +211,7 @@ void DoState(PointerWrap &p)
void UpdateInterrupts(); void UpdateInterrupts();
void Update_ARAM_DMA(); void Do_ARAM_DMA();
void WriteARAM(u8 _iValue, u32 _iAddress); void WriteARAM(u8 _iValue, u32 _iAddress);
bool Update_DSP_ReadRegister(); bool Update_DSP_ReadRegister();
void Update_DSP_WriteRegister(); void Update_DSP_WriteRegister();
@ -433,16 +430,13 @@ void Write16(const u16 _Value, const u32 _Address)
case AR_DMA_ARADDR_L: case AR_DMA_ARADDR_L:
g_arDMA.ARAddr = (g_arDMA.ARAddr & 0xFFFF0000) | (_Value); break; g_arDMA.ARAddr = (g_arDMA.ARAddr & 0xFFFF0000) | (_Value); break;
case AR_DMA_CNT_H: case AR_DMA_CNT_H:
g_arDMA.Cnt.Hex = (g_arDMA.Cnt.Hex & 0xFFFF) | (_Value<<16); g_arDMA.Cnt.Hex = (g_arDMA.Cnt.Hex & 0xFFFF) | (_Value<<16);
g_arDMA.CntValid[0] = true;
Update_ARAM_DMA();
break; break;
case AR_DMA_CNT_L: case AR_DMA_CNT_L:
g_arDMA.Cnt.Hex = (g_arDMA.Cnt.Hex & 0xFFFF0000) | (_Value); g_arDMA.Cnt.Hex = (g_arDMA.Cnt.Hex & 0xFFFF0000) | (_Value);
g_arDMA.CntValid[1] = true; Do_ARAM_DMA();
Update_ARAM_DMA();
break; break;
// Audio DMA_REGS 0x5030+ // Audio DMA_REGS 0x5030+
@ -472,39 +466,6 @@ void Write16(const u16 _Value, const u32 _Address)
} }
} }
// This happens at 4 khz, since 32 bytes at 4khz = 4 bytes at 32 khz (16bit stereo pcm)
void UpdateAudioDMA()
{
if (g_audioDMA.AudioDMAControl.Enable && g_audioDMA.BlocksLeft)
{
// Read audio at g_audioDMA.ReadAddress in RAM and push onto an
// external audio fifo in the emulator, to be mixed with the disc
// streaming output. If that audio queue fills up, we delay the
// emulator.
// AyuanX: let's do it in a bundle to speed up
if (g_audioDMA.BlocksLeft == g_audioDMA.AudioDMAControl.NumBlocks)
dsp_plugin->DSP_SendAIBuffer(g_audioDMA.SourceAddress, g_audioDMA.AudioDMAControl.NumBlocks * 8);
// g_audioDMA.ReadAddress += 32;
g_audioDMA.BlocksLeft--;
if (g_audioDMA.BlocksLeft == 0)
{
GenerateDSPInterrupt(DSP::INT_AID);
// g_audioDMA.ReadAddress = g_audioDMA.SourceAddress;
g_audioDMA.BlocksLeft = g_audioDMA.AudioDMAControl.NumBlocks;
// DEBUG_LOG(DSPLLE, "ADMA read addresses: %08x", g_audioDMA.ReadAddress);
}
}
else
{
// Send silence. Yeah, it's a bit of a waste to sample rate convert
// silence. or hm. Maybe we shouldn't do this :)
// dsp->DSP_SendAIBuffer(0, AudioInterface::GetDSPSampleRate());
}
}
void Read32(u32& _uReturnValue, const u32 _iAddress) void Read32(u32& _uReturnValue, const u32 _iAddress)
{ {
INFO_LOG(DSPINTERFACE, "DSPInterface(r32) 0x%08x", _iAddress); INFO_LOG(DSPINTERFACE, "DSPInterface(r32) 0x%08x", _iAddress);
@ -547,9 +508,8 @@ void Write32(const u32 _iValue, const u32 _iAddress)
break; break;
case AR_DMA_CNT_H: case AR_DMA_CNT_H:
g_arDMA.Cnt.Hex = _iValue; g_arDMA.Cnt.Hex = _iValue;
g_arDMA.CntValid[0] = g_arDMA.CntValid[1] = true; Do_ARAM_DMA();
Update_ARAM_DMA();
break; break;
default: default:
@ -593,52 +553,74 @@ void GenerateDSPInterruptFromPlugin(DSPInterruptType type, bool _bSet)
0, et_GenerateDSPInterrupt, type | (_bSet<<16)); 0, et_GenerateDSPInterrupt, type | (_bSet<<16));
} }
void Update_ARAM_DMA() // This happens at 4 khz, since 32 bytes at 4khz = 4 bytes at 32 khz (16bit stereo pcm)
void UpdateAudioDMA()
{ {
// check if the count reg is valid if (g_audioDMA.AudioDMAControl.Enable && g_audioDMA.BlocksLeft)
if (!g_arDMA.CntValid[0] || !g_arDMA.CntValid[1])
return;
g_arDMA.CntValid[0] = g_arDMA.CntValid[1] = false;
INFO_LOG(DSPINTERFACE, "ARAM DMA triggered");
//TODO: speedup
if (g_arDMA.Cnt.dir)
{ {
//read from ARAM // Read audio at g_audioDMA.ReadAddress in RAM and push onto an
INFO_LOG(DSPINTERFACE, "DMA copy %08x bytes from ARAM %08x to Mem: %08x",g_arDMA.Cnt.count, g_arDMA.ARAddr, g_arDMA.MMAddr); // external audio fifo in the emulator, to be mixed with the disc
u32 iMemAddress = g_arDMA.MMAddr; // streaming output. If that audio queue fills up, we delay the
u32 iARAMAddress = g_arDMA.ARAddr; // emulator.
// TODO(??): sanity check instead of writing bogus data?
for (u32 i = 0; i < g_arDMA.Cnt.count; i++)
{
u32 tmp = (iARAMAddress < g_ARAM.size) ? g_ARAM.ptr[iARAMAddress] : 0x05050505;
Memory::Write_U8(tmp, iMemAddress);
iMemAddress++; // AyuanX: let's do it in a bundle to speed up
iARAMAddress++; if (g_audioDMA.BlocksLeft == g_audioDMA.AudioDMAControl.NumBlocks)
dsp_plugin->DSP_SendAIBuffer(g_audioDMA.SourceAddress, g_audioDMA.AudioDMAControl.NumBlocks * 8);
// g_audioDMA.ReadAddress += 32;
g_audioDMA.BlocksLeft--;
if (g_audioDMA.BlocksLeft == 0)
{
GenerateDSPInterrupt(DSP::INT_AID);
// g_audioDMA.ReadAddress = g_audioDMA.SourceAddress;
g_audioDMA.BlocksLeft = g_audioDMA.AudioDMAControl.NumBlocks;
// DEBUG_LOG(DSPLLE, "ADMA read addresses: %08x", g_audioDMA.ReadAddress);
} }
} }
else else
{ {
u32 iMemAddress = g_arDMA.MMAddr; // Send silence. Yeah, it's a bit of a waste to sample rate convert
u32 iARAMAddress = g_arDMA.ARAddr; // silence. or hm. Maybe we shouldn't do this :)
// dsp->DSP_SendAIBuffer(0, AudioInterface::GetDSPSampleRate());
}
}
//write to g_ARAM void Do_ARAM_DMA()
INFO_LOG(DSPINTERFACE, "DMA copy %08x bytes from Mem %08x to ARAM %08x (sound data loaded)", {
g_arDMA.Cnt.count, g_arDMA.MMAddr, g_arDMA.ARAddr); // Real hardware DMAs in 32byte chunks, but we can get by with 8byte chunks
for (u32 i = 0; i < g_arDMA.Cnt.count; i++) if (g_arDMA.Cnt.dir)
{
// ARAM -> MRAM
INFO_LOG(DSPINTERFACE, "DMA %08x bytes from ARAM %08x to MRAM %08x",
g_arDMA.Cnt.count, g_arDMA.ARAddr, g_arDMA.MMAddr);
while (g_arDMA.Cnt.count)
{ {
if (iARAMAddress < g_ARAM.size) Memory::Write_U64_Swap(*(u64*)&g_ARAM.ptr[g_arDMA.ARAddr], g_arDMA.MMAddr);
g_ARAM.ptr[iARAMAddress] = Memory::Read_U8(iMemAddress); g_arDMA.MMAddr += 8;
g_arDMA.ARAddr += 8;
g_arDMA.Cnt.count -= 8;
}
}
else
{
// MRAM -> ARAM
INFO_LOG(DSPINTERFACE, "DMA %08x bytes from MRAM %08x to ARAM %08x",
g_arDMA.Cnt.count, g_arDMA.MMAddr, g_arDMA.ARAddr);
iMemAddress++; while (g_arDMA.Cnt.count)
iARAMAddress++; {
if (g_arDMA.ARAddr < g_ARAM.size)
{
*(u64*)&g_ARAM.ptr[g_arDMA.ARAddr] = Common::swap64(Memory::Read_U64(g_arDMA.MMAddr));
g_arDMA.MMAddr += 8;
g_arDMA.ARAddr += 8;
}
g_arDMA.Cnt.count -= 8;
} }
} }
g_arDMA.Cnt.count = 0;
GenerateDSPInterrupt(INT_ARAM); GenerateDSPInterrupt(INT_ARAM);
} }

View File

@ -443,7 +443,7 @@ void Write_U64(const u64 _Data, const u32 _Address)
WriteToHardware<u64>(_Address, _Data, _Address + 4, FLAG_WRITE); WriteToHardware<u64>(_Address, _Data, _Address + 4, FLAG_WRITE);
} }
void Write_U64_Swap(const u32 _Data, const u32 _Address) { void Write_U64_Swap(const u64 _Data, const u32 _Address) {
Write_U64(Common::swap64(_Data), _Address); Write_U64(Common::swap64(_Data), _Address);
} }