diff --git a/Source/Core/Core/HW/DSP.cpp b/Source/Core/Core/HW/DSP.cpp index 821ba69925..fbf48b66cf 100644 --- a/Source/Core/Core/HW/DSP.cpp +++ b/Source/Core/Core/HW/DSP.cpp @@ -30,6 +30,7 @@ #include "CPU.h" #include "MemoryUtil.h" #include "Memmap.h" +#include "MMIO.h" #include "ProcessorInterface.h" #include "AudioInterface.h" #include "../PowerPC/PowerPC.h" @@ -287,124 +288,89 @@ void Shutdown() dsp_emulator = NULL; } -void Read16(u16& _uReturnValue, const u32 _iAddress) +void RegisterMMIO(MMIO::Mapping* mmio, u32 base) { - switch (_iAddress & 0xFFFF) + // Declare all the boilerplate direct MMIOs. + struct { + u32 addr; + u16* ptr; + bool align_writes_on_32_bytes; + } directly_mapped_vars[] = { + { AR_INFO, &g_ARAM_Info.Hex }, + { AR_MODE, &g_AR_MODE }, + { AR_REFRESH, &g_AR_REFRESH }, + { AR_DMA_MMADDR_H, MMIO::Utils::HighPart(&g_arDMA.MMAddr) }, + { AR_DMA_MMADDR_L, MMIO::Utils::LowPart(&g_arDMA.MMAddr), true }, + { AR_DMA_ARADDR_H, MMIO::Utils::HighPart(&g_arDMA.ARAddr) }, + { AR_DMA_ARADDR_L, MMIO::Utils::LowPart(&g_arDMA.ARAddr), true }, + { AR_DMA_CNT_H, MMIO::Utils::HighPart(&g_arDMA.Cnt.Hex) }, + // AR_DMA_CNT_L triggers DMA + { AUDIO_DMA_START_HI, MMIO::Utils::HighPart(&g_audioDMA.SourceAddress) }, + { AUDIO_DMA_START_LO, MMIO::Utils::LowPart(&g_audioDMA.SourceAddress) }, + }; + for (auto& mapped_var : directly_mapped_vars) { - // DSP - case DSP_MAIL_TO_DSP_HI: - if (dsp_slice > DSP_MAIL_SLICE && dsp_is_lle) { - dsp_emulator->DSP_Update(DSP_MAIL_SLICE); - dsp_slice -= DSP_MAIL_SLICE; - } - _uReturnValue = dsp_emulator->DSP_ReadMailBoxHigh(true); - break; - - case DSP_MAIL_TO_DSP_LO: - _uReturnValue = dsp_emulator->DSP_ReadMailBoxLow(true); - break; - - case DSP_MAIL_FROM_DSP_HI: - if (dsp_slice > DSP_MAIL_SLICE && dsp_is_lle) { - dsp_emulator->DSP_Update(DSP_MAIL_SLICE); - dsp_slice -= DSP_MAIL_SLICE; - } - _uReturnValue = dsp_emulator->DSP_ReadMailBoxHigh(false); - break; - - case DSP_MAIL_FROM_DSP_LO: - _uReturnValue = dsp_emulator->DSP_ReadMailBoxLow(false); - break; - - case DSP_CONTROL: - _uReturnValue = (g_dspState.DSPControl.Hex & ~DSP_CONTROL_MASK) | - (dsp_emulator->DSP_ReadControlRegister() & DSP_CONTROL_MASK); - break; - - // ARAM - case AR_INFO: - //PanicAlert("Read %x %x", g_ARAM_Info.Hex,PowerPC::ppcState.pc); - _uReturnValue = g_ARAM_Info.Hex; - break; - - case AR_MODE: - _uReturnValue = g_AR_MODE; - break; - - case AR_REFRESH: - _uReturnValue = g_AR_REFRESH; - break; - - case AR_DMA_MMADDR_H: _uReturnValue = g_arDMA.MMAddr >> 16; return; - case AR_DMA_MMADDR_L: _uReturnValue = g_arDMA.MMAddr & 0xFFFF; return; - case AR_DMA_ARADDR_H: _uReturnValue = g_arDMA.ARAddr >> 16; return; - case AR_DMA_ARADDR_L: _uReturnValue = g_arDMA.ARAddr & 0xFFFF; return; - case AR_DMA_CNT_H: _uReturnValue = g_arDMA.Cnt.Hex >> 16; return; - case AR_DMA_CNT_L: _uReturnValue = g_arDMA.Cnt.Hex & 0xFFFF; return; - - // AI - case AUDIO_DMA_BLOCKS_LEFT: - _uReturnValue = g_audioDMA.BlocksLeft > 0 ? g_audioDMA.BlocksLeft - 1 : 0; // AUDIO_DMA_BLOCKS_LEFT is zero based - break; - - case AUDIO_DMA_START_LO: - _uReturnValue = g_audioDMA.SourceAddress & 0xFFFF; - break; - - case AUDIO_DMA_START_HI: - _uReturnValue = g_audioDMA.SourceAddress >> 16; - break; - - case AUDIO_DMA_CONTROL_LEN: - _uReturnValue = g_audioDMA.AudioDMAControl.Hex; - break; - - default: - _uReturnValue = 0; - _dbg_assert_(DSPINTERFACE,0); - break; + u16 write_mask = mapped_var.align_writes_on_32_bytes ? 0xFFE0 : 0xFFFF; + mmio->Register(base | mapped_var.addr, + MMIO::DirectRead(mapped_var.ptr), + MMIO::DirectWrite(mapped_var.ptr, write_mask) + ); } - if (_iAddress != (0xCC000000 + DSP_MAIL_FROM_DSP_HI)) - { - DEBUG_LOG(DSPINTERFACE, "DSPInterface(r16) 0x%08x (0x%04x) (%08x)", _iAddress, _uReturnValue, PowerPC::ppcState.pc); - } -} + // DSP mail MMIOs call DSP emulator functions to get results or write data. + mmio->Register(base | DSP_MAIL_TO_DSP_HI, + MMIO::ComplexRead([](u32) { + if (dsp_slice > DSP_MAIL_SLICE && dsp_is_lle) + { + dsp_emulator->DSP_Update(DSP_MAIL_SLICE); + dsp_slice -= DSP_MAIL_SLICE; + } + return dsp_emulator->DSP_ReadMailBoxHigh(true); + }), + MMIO::ComplexWrite([](u32, u16 val) { + dsp_emulator->DSP_WriteMailBoxHigh(true, val); + }) + ); + mmio->Register(base | DSP_MAIL_TO_DSP_LO, + MMIO::ComplexRead([](u32) { + return dsp_emulator->DSP_ReadMailBoxLow(true); + }), + MMIO::ComplexWrite([](u32, u16 val) { + dsp_emulator->DSP_WriteMailBoxLow(true, val); + }) + ); + mmio->Register(base | DSP_MAIL_FROM_DSP_HI, + MMIO::ComplexRead([](u32) { + if (dsp_slice > DSP_MAIL_SLICE && dsp_is_lle) + { + dsp_emulator->DSP_Update(DSP_MAIL_SLICE); + dsp_slice -= DSP_MAIL_SLICE; + } + return dsp_emulator->DSP_ReadMailBoxHigh(false); + }), + MMIO::InvalidWrite() + ); + mmio->Register(base | DSP_MAIL_FROM_DSP_LO, + MMIO::ComplexRead([](u32) { + return dsp_emulator->DSP_ReadMailBoxLow(false); + }), + MMIO::InvalidWrite() + ); -void Write16(const u16 _Value, const u32 _Address) -{ - DEBUG_LOG(DSPINTERFACE, "DSPInterface(w16) 0x%08x (0x%04x) (%08x)", _Address, _Value, PowerPC::ppcState.pc); - - switch (_Address & 0xFFFF) - { - // DSP - case DSP_MAIL_TO_DSP_HI: - dsp_emulator->DSP_WriteMailBoxHigh(true, _Value); - break; - - case DSP_MAIL_TO_DSP_LO: - dsp_emulator->DSP_WriteMailBoxLow(true, _Value); - break; - - case DSP_MAIL_FROM_DSP_HI: - _dbg_assert_msg_(DSPINTERFACE, 0, "W16: DSP_MAIL_FROM_DSP_HI"); - break; - - case DSP_MAIL_FROM_DSP_LO: - _dbg_assert_msg_(DSPINTERFACE, 0, "W16: DSP_MAIL_FROM_DSP_LO"); - break; - - // Control Register - case DSP_CONTROL: - { + mmio->Register(base | DSP_CONTROL, + MMIO::ComplexRead([](u32) { + return (g_dspState.DSPControl.Hex & ~DSP_CONTROL_MASK) | + (dsp_emulator->DSP_ReadControlRegister() & DSP_CONTROL_MASK); + }), + MMIO::ComplexWrite([](u32, u16 val) { UDSPControl tmpControl; - tmpControl.Hex = (_Value & ~DSP_CONTROL_MASK) | - (dsp_emulator->DSP_WriteControlRegister(_Value) & DSP_CONTROL_MASK); + tmpControl.Hex = (val & ~DSP_CONTROL_MASK) | + (dsp_emulator->DSP_WriteControlRegister(val) & DSP_CONTROL_MASK); // Not really sure if this is correct, but it works... // Kind of a hack because DSP_CONTROL_MASK should make this bit // only viewable to dsp emulator - if (_Value & 1 /*DSPReset*/) + if (val & 1 /*DSPReset*/) { g_audioDMA.AudioDMAControl.Hex = 0; } @@ -430,177 +396,73 @@ void Write16(const u16 _Value, const u32 _Address) g_dspState.DSPControl.pad = tmpControl.pad; if (g_dspState.DSPControl.pad != 0) { - PanicAlert("DSPInterface (w) g_dspState.DSPControl (CC00500A) gets a value with junk in the padding %08x", _Value); + PanicAlert("DSPInterface (w) g_dspState.DSPControl (CC00500A) gets a value with junk in the padding %08x", val); } UpdateInterrupts(); - } - break; + }) + ); - // ARAM - // DMA back and forth between ARAM and RAM - case AR_INFO: - //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; + // ARAM MMIO controlling the DMA start. + mmio->Register(base | AR_DMA_CNT_L, + MMIO::DirectRead(MMIO::Utils::LowPart(&g_arDMA.Cnt.Hex)), + MMIO::ComplexWrite([](u32, u16 val) { + g_arDMA.Cnt.Hex = (g_arDMA.Cnt.Hex & 0xFFFF0000) | (val & ~31); + Do_ARAM_DMA(); + }) + ); - // 0x43 - // Monster Hunter Tri, DKCR + // Audio DMA MMIO controlling the DMA start. + mmio->Register(base | AUDIO_DMA_CONTROL_LEN, + MMIO::DirectRead(&g_audioDMA.AudioDMAControl.Hex), + MMIO::ComplexWrite([](u32, u16 val) { + g_audioDMA.AudioDMAControl.Hex = val; + g_audioDMA.ReadAddress = g_audioDMA.SourceAddress; + g_audioDMA.BlocksLeft = g_audioDMA.AudioDMAControl.NumBlocks; + }) + ); - // 0x43, 0x63: - // Rebel Strike, Clone Wars, WWE DOR2, Mario Golf + // Audio DMA blocks remaining is invalid to write to, and requires logic on + // the read side. + mmio->Register(base | AUDIO_DMA_BLOCKS_LEFT, + MMIO::ComplexRead([](u32) { + return (g_audioDMA.BlocksLeft > 0 ? g_audioDMA.BlocksLeft - 1 : 0); + }), + MMIO::InvalidWrite() + ); - // 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: - g_AR_MODE = _Value; - break; - - case AR_REFRESH: - // 0x9c -> Set by Eternal Darkness - g_AR_REFRESH = _Value; - break; - - case AR_DMA_MMADDR_H: - g_arDMA.MMAddr = (g_arDMA.MMAddr & 0xFFFF) | (_Value<<16); - break; - - case AR_DMA_MMADDR_L: - // Align MMAddr to the 32 byte boundary. Verified on real HW - g_arDMA.MMAddr = ((g_arDMA.MMAddr & 0xFFFF0000) | (_Value)) & ~31; - break; - - case AR_DMA_ARADDR_H: - g_arDMA.ARAddr = (g_arDMA.ARAddr & 0xFFFF) | (_Value<<16); - break; - - case AR_DMA_ARADDR_L: - // Align ARAddr to the 32 byte boundary. Verified on real HW - g_arDMA.ARAddr = ((g_arDMA.ARAddr & 0xFFFF0000) | (_Value)) & ~31; - break; - - case AR_DMA_CNT_H: - g_arDMA.Cnt.Hex = (g_arDMA.Cnt.Hex & 0xFFFF) | (_Value<<16); - break; - - case AR_DMA_CNT_L: - // Align count to the 32 byte boundary. Verified on real HW - g_arDMA.Cnt.Hex = ((g_arDMA.Cnt.Hex & 0xFFFF0000) | (_Value)) & ~31; - Do_ARAM_DMA(); - break; - - // AI - // This is the DMA that goes straight out the speaker. - case AUDIO_DMA_START_HI: - g_audioDMA.SourceAddress = (g_audioDMA.SourceAddress & 0xFFFF) | (_Value<<16); - break; - - case AUDIO_DMA_START_LO: - g_audioDMA.SourceAddress = (g_audioDMA.SourceAddress & 0xFFFF0000) | (_Value); - break; - - case AUDIO_DMA_CONTROL_LEN: // called by AIStartDMA() - g_audioDMA.AudioDMAControl.Hex = _Value; - g_audioDMA.ReadAddress = g_audioDMA.SourceAddress; - g_audioDMA.BlocksLeft = g_audioDMA.AudioDMAControl.NumBlocks; - INFO_LOG(DSPINTERFACE, "AID DMA started - source address %08x, length %i blocks", g_audioDMA.SourceAddress, g_audioDMA.AudioDMAControl.NumBlocks); - break; - - case AUDIO_DMA_BLOCKS_LEFT: - _dbg_assert_(DSPINTERFACE,0); - break; - - default: - _dbg_assert_(DSPINTERFACE,0); - break; + // 32 bit reads/writes are a combination of two 16 bit accesses. + for (int i = 0; i < 0x1000; i += 4) + { + mmio->Register(base | i, + MMIO::ReadToSmaller(mmio, base | i, base | (i + 2)), + MMIO::WriteToSmaller(mmio, base | i, base | (i + 2)) + ); } } +void Read16(u16& _uReturnValue, const u32 _iAddress) +{ + // HACK: Remove this function when the new MMIO interface is used. + Memory::mmio_mapping->Read(_iAddress, _uReturnValue); +} + +void Write16(const u16 _Value, const u32 _Address) +{ + // HACK: Remove this function when the new MMIO interface is used. + Memory::mmio_mapping->Write(_Address, _Value); +} + void Read32(u32& _uReturnValue, const u32 _iAddress) { - INFO_LOG(DSPINTERFACE, "DSPInterface(r32) 0x%08x", _iAddress); - - switch (_iAddress & 0xFFFF) - { - // DSP - case DSP_MAIL_TO_DSP_HI: - _uReturnValue = (dsp_emulator->DSP_ReadMailBoxHigh(true) << 16) | dsp_emulator->DSP_ReadMailBoxLow(true); - break; - - // AI - case AUDIO_DMA_START_HI: - _uReturnValue = g_audioDMA.SourceAddress; - break; - - // ARAM - case AR_DMA_ARADDR_H: - _uReturnValue = g_arDMA.ARAddr; - break; - - case AR_DMA_CNT_H: - _uReturnValue = g_arDMA.Cnt.Hex; - break; - - case AR_DMA_MMADDR_H: - _uReturnValue = g_arDMA.MMAddr; - break; - - default: - _uReturnValue = 0; - _dbg_assert_(DSPINTERFACE,0); - break; - } + // HACK: Remove this function when the new MMIO interface is used. + Memory::mmio_mapping->Read(_iAddress, _uReturnValue); } void Write32(const u32 _iValue, const u32 _iAddress) { - INFO_LOG(DSPINTERFACE, "DSPInterface(w32) 0x%08x 0x%08x", _iValue, _iAddress); - - switch (_iAddress & 0xFFFF) - { - // DSP - case DSP_MAIL_TO_DSP_HI: - dsp_emulator->DSP_WriteMailBoxHigh(true, _iValue >> 16); - dsp_emulator->DSP_WriteMailBoxLow(true, (u16)_iValue); - break; - - // AI - case AUDIO_DMA_START_HI: - g_audioDMA.SourceAddress = _iValue; - break; - - // ARAM - case AR_DMA_MMADDR_H: - g_arDMA.MMAddr = _iValue & ~31; - break; - - case AR_DMA_ARADDR_H: - g_arDMA.ARAddr = _iValue & ~31; - break; - - case AR_DMA_CNT_H: - g_arDMA.Cnt.Hex = _iValue & ~31; - Do_ARAM_DMA(); - break; - - default: - _dbg_assert_(DSPINTERFACE,0); - break; - } + // HACK: Remove this function when the new MMIO interface is used. + Memory::mmio_mapping->Write(_iAddress, _iValue); } diff --git a/Source/Core/Core/HW/DSP.h b/Source/Core/Core/HW/DSP.h index 002207c842..c9bd622d75 100644 --- a/Source/Core/Core/HW/DSP.h +++ b/Source/Core/Core/HW/DSP.h @@ -7,6 +7,7 @@ #include "Common.h" class PointerWrap; class DSPEmulator; +namespace MMIO { class Mapping; } namespace DSP { @@ -28,6 +29,8 @@ enum void Init(bool hle); void Shutdown(); +void RegisterMMIO(MMIO::Mapping* mmio, u32 base); + DSPEmulator *GetDSPEmulator(); void DoState(PointerWrap &p); diff --git a/Source/Core/Core/HW/Memmap.cpp b/Source/Core/Core/HW/Memmap.cpp index 13d031518c..29181b5c40 100644 --- a/Source/Core/Core/HW/Memmap.cpp +++ b/Source/Core/Core/HW/Memmap.cpp @@ -313,6 +313,7 @@ void InitMMIO(MMIO::Mapping* mmio) VideoInterface::RegisterMMIO(mmio, 0xCC002000); ProcessorInterface::RegisterMMIO(mmio, 0xCC003000); MemoryInterface::RegisterMMIO(mmio, 0xCC004000); + DSP::RegisterMMIO(mmio, 0xCC005000); } void InitMMIOWii(MMIO::Mapping* mmio) @@ -320,6 +321,7 @@ void InitMMIOWii(MMIO::Mapping* mmio) VideoInterface::RegisterMMIO(mmio, 0xCC002000); ProcessorInterface::RegisterMMIO(mmio, 0xCC003000); MemoryInterface::RegisterMMIO(mmio, 0xCC004000); + DSP::RegisterMMIO(mmio, 0xCC005000); } writeFn32 GetHWWriteFun32(const u32 _Address)