Added preliminary support for ARAM memory map mode "4".

Fixes issue 3410.
This commit is contained in:
skidau 2012-05-01 22:05:48 +10:00
parent 2540fe0606
commit 1b15cd0b60
2 changed files with 51 additions and 17 deletions

View File

@ -354,7 +354,7 @@ void Read16(u16& _uReturnValue, const u32 _iAddress)
// AI
case AUDIO_DMA_BLOCKS_LEFT:
_uReturnValue = g_audioDMA.BlocksLeft - 1; // AUDIO_DMA_BLOCKS_LEFT is zero based
_uReturnValue = g_audioDMA.BlocksLeft > 0 ? g_audioDMA.BlocksLeft - 1 : 0; // AUDIO_DMA_BLOCKS_LEFT is zero based
break;
case AUDIO_DMA_START_LO:
@ -435,7 +435,7 @@ void Write16(const u16 _Value, const u32 _Address)
if (tmpControl.ARAM) g_dspState.DSPControl.ARAM = 0;
if (tmpControl.DSP) g_dspState.DSPControl.DSP = 0;
// g_ARAM
// g_ARAM (line below should be commented out to emulate the DMA wait time)
g_dspState.DSPControl.DMAState = 0; // keep g_ARAM DMA State zero
// unknown
@ -453,14 +453,30 @@ void Write16(const u16 _Value, const u32 _Address)
// ARAM
// DMA back and forth between ARAM and RAM
case AR_INFO:
//PanicAlert("write %x %x", _Value,PowerPC::ppcState.pc);
//PanicAlert("AR_INFO %x PC: %x", _Value, PowerPC::ppcState.pc);
ERROR_LOG(DSPINTERFACE, "AR_INFO %x PC: %x", _Value, PowerPC::ppcState.pc);
g_ARAM_Info.Hex = _Value;
// 0x43
// Monster Hunter Tri, DKCR
// 0x43, 0x63:
// Rebel Strike, Clone Wars, WWE DOR2, Mario Golf
// 0x43, 0x64, 0x63
// Transworld Surf, Smashing Drive, SSBM, Cel Damage
// __OSInitAudioSystem sets to 0x43 -> expects 16bit adressing and mapping to dsp iram?
// __OSCheckSize sets = 0x20 | 3 (keeps upper bits)
// 0x23 -> Zelda standard mode (standard ARAM access ??)
// 0x43 -> Set by __OSInitAudioSystem
// 0x58 -> Transworld Surf, Cel Damage, SSBM
// 0x60 -> Transworld Surf, Cel Damage, SSBM
// 0x63 -> ARCheckSize Mode (access AR-registers ??) or no exception ??
// 0x64 -> Transworld Surf, Cel Damage, SSBM
// 0x00 -> Switch to external ARAM
// 0x04 -> Switch to internal ARAM
break;
case AR_MODE:
@ -621,7 +637,7 @@ void GenerateDSPInterrupt(DSPInterruptType type, bool _bSet)
switch (type)
{
case INT_DSP: g_dspState.DSPControl.DSP = _bSet ? 1 : 0; break;
case INT_ARAM: g_dspState.DSPControl.ARAM = _bSet ? 1 : 0; break;
case INT_ARAM: g_dspState.DSPControl.ARAM = _bSet ? 1 : 0; if (_bSet) g_dspState.DSPControl.DMAState = 0; break;
case INT_AID: g_dspState.DSPControl.AID = _bSet ? 1 : 0; break;
}
@ -683,6 +699,9 @@ void Do_ARAM_DMA()
// seems like a good estimate
CoreTiming::ScheduleEvent_Threadsafe(g_arDMA.Cnt.count >> 1, et_GenerateDSPInterrupt, INT_ARAM | (1<<16));
// Uncomment the line below to emulate the DMA wait time.
//g_dspState.DSPControl.DMAState = 1;
// Real hardware DMAs in 32byte chunks, but we can get by with 8byte chunks
if (g_arDMA.Cnt.dir)
{
@ -694,15 +713,20 @@ void Do_ARAM_DMA()
g_arDMA.ARAddr &= 0x3ffffff;
g_arDMA.MMAddr &= 0x3ffffff;
// Transworld Surf (GTVE70) needs this
if (g_arDMA.ARAddr > g_ARAM.size)
g_arDMA.ARAddr -= g_ARAM.size;
if (g_arDMA.ARAddr < g_ARAM.size)
{
while (g_arDMA.Cnt.count)
{
Memory::Write_U64_Swap(*(u64*)&g_ARAM.ptr[g_arDMA.ARAddr & ARAM_MASK], g_arDMA.MMAddr);
if ((g_ARAM_Info.Hex & 0xf) == 3)
{
Memory::Write_U64_Swap(*(u64*)&g_ARAM.ptr[g_arDMA.ARAddr & g_ARAM.mask], g_arDMA.MMAddr);
}
else if ((g_ARAM_Info.Hex & 0xf) == 4)
{
Memory::Write_U64_Swap(*(u64*)&g_ARAM.ptr[g_arDMA.ARAddr & g_ARAM.mask], g_arDMA.MMAddr);
}
else
Memory::Write_U64_Swap(*(u64*)&g_ARAM.ptr[g_arDMA.ARAddr & g_ARAM.mask], g_arDMA.MMAddr);
g_arDMA.MMAddr += 8;
g_arDMA.ARAddr += 8;
g_arDMA.Cnt.count -= 8;
@ -710,7 +734,7 @@ void Do_ARAM_DMA()
}
else
{
// Returns zeroes on out of bounds reads (verified on real HW)
// Assuming no external ARAM installed; returns zeroes on out of bounds reads (verified on real HW)
while (g_arDMA.Cnt.count)
{
Memory::Write_U64(0, g_arDMA.MMAddr);
@ -730,15 +754,25 @@ void Do_ARAM_DMA()
g_arDMA.ARAddr &= 0x3ffffff;
g_arDMA.MMAddr &= 0x3ffffff;
// Transworld Surf (GTVE70) needs this
if (g_arDMA.ARAddr > g_ARAM.size)
g_arDMA.ARAddr -= g_ARAM.size;
if (g_arDMA.ARAddr < g_ARAM.size)
{
while (g_arDMA.Cnt.count)
{
*(u64*)&g_ARAM.ptr[g_arDMA.ARAddr & ARAM_MASK] = Common::swap64(Memory::Read_U64(g_arDMA.MMAddr));
if ((g_ARAM_Info.Hex & 0xf) == 3)
{
*(u64*)&g_ARAM.ptr[g_arDMA.ARAddr & g_ARAM.mask] = Common::swap64(Memory::Read_U64(g_arDMA.MMAddr));
}
else if ((g_ARAM_Info.Hex & 0xf) == 4)
{
if (g_arDMA.ARAddr < 0x400000)
{
*(u64*)&g_ARAM.ptr[(g_arDMA.ARAddr + 0x400000) & g_ARAM.mask] = Common::swap64(Memory::Read_U64(g_arDMA.MMAddr));
}
*(u64*)&g_ARAM.ptr[g_arDMA.ARAddr & g_ARAM.mask] = Common::swap64(Memory::Read_U64(g_arDMA.MMAddr));
}
else
*(u64*)&g_ARAM.ptr[g_arDMA.ARAddr & g_ARAM.mask] = Common::swap64(Memory::Read_U64(g_arDMA.MMAddr));
g_arDMA.MMAddr += 8;
g_arDMA.ARAddr += 8;
g_arDMA.Cnt.count -= 8;
@ -746,7 +780,7 @@ void Do_ARAM_DMA()
}
else
{
// Writes nothing to ARAM when out of bounds (verified on real HW)
// Assuming no external ARAM installed; writes nothing to ARAM when out of bounds (verified on real HW)
g_arDMA.MMAddr += g_arDMA.Cnt.count;
g_arDMA.ARAddr += g_arDMA.Cnt.count;
g_arDMA.Cnt.count = 0;

View File

@ -504,7 +504,7 @@ void CheckExternalExceptions()
// clear MSR as specified
//MSR &= ~0x04EF36; // 0x04FF36 also clears ME (only for machine check exception)
// set to exception type entry point
//NPC = 0x80000x00;
//NPC = 0x00000x00;
// EXTERNAL INTERRUPT
if (MSR & 0x0008000) //hacky...the exception shouldn't be generated if EE isn't set...