MMIO: Port the DSP/ARAM/AI MMIOs to the new interface.

This commit is contained in:
Pierre Bourdon 2014-01-25 15:57:07 +01:00
parent b7a0c34906
commit 63990787fd
3 changed files with 130 additions and 263 deletions

View File

@ -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<u16>(mapped_var.ptr),
MMIO::DirectWrite<u16>(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<u16>([](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<u16>([](u32, u16 val) {
dsp_emulator->DSP_WriteMailBoxHigh(true, val);
})
);
mmio->Register(base | DSP_MAIL_TO_DSP_LO,
MMIO::ComplexRead<u16>([](u32) {
return dsp_emulator->DSP_ReadMailBoxLow(true);
}),
MMIO::ComplexWrite<u16>([](u32, u16 val) {
dsp_emulator->DSP_WriteMailBoxLow(true, val);
})
);
mmio->Register(base | DSP_MAIL_FROM_DSP_HI,
MMIO::ComplexRead<u16>([](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<u16>()
);
mmio->Register(base | DSP_MAIL_FROM_DSP_LO,
MMIO::ComplexRead<u16>([](u32) {
return dsp_emulator->DSP_ReadMailBoxLow(false);
}),
MMIO::InvalidWrite<u16>()
);
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<u16>([](u32) {
return (g_dspState.DSPControl.Hex & ~DSP_CONTROL_MASK) |
(dsp_emulator->DSP_ReadControlRegister() & DSP_CONTROL_MASK);
}),
MMIO::ComplexWrite<u16>([](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<u16>(MMIO::Utils::LowPart(&g_arDMA.Cnt.Hex)),
MMIO::ComplexWrite<u16>([](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<u16>(&g_audioDMA.AudioDMAControl.Hex),
MMIO::ComplexWrite<u16>([](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<u16>([](u32) {
return (g_audioDMA.BlocksLeft > 0 ? g_audioDMA.BlocksLeft - 1 : 0);
}),
MMIO::InvalidWrite<u16>()
);
// 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<u32>(mmio, base | i, base | (i + 2)),
MMIO::WriteToSmaller<u32>(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);
}

View File

@ -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);

View File

@ -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)