MMIO: Port the DSP/ARAM/AI MMIOs to the new interface.
This commit is contained in:
parent
b7a0c34906
commit
63990787fd
|
@ -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)
|
||||
{
|
||||
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)
|
||||
);
|
||||
}
|
||||
|
||||
// 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
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
_uReturnValue = dsp_emulator->DSP_ReadMailBoxHigh(false);
|
||||
break;
|
||||
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>()
|
||||
);
|
||||
|
||||
case DSP_MAIL_FROM_DSP_LO:
|
||||
_uReturnValue = dsp_emulator->DSP_ReadMailBoxLow(false);
|
||||
break;
|
||||
|
||||
case DSP_CONTROL:
|
||||
_uReturnValue = (g_dspState.DSPControl.Hex & ~DSP_CONTROL_MASK) |
|
||||
mmio->Register(base | DSP_CONTROL,
|
||||
MMIO::ComplexRead<u16>([](u32) {
|
||||
return (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;
|
||||
}
|
||||
|
||||
if (_iAddress != (0xCC000000 + DSP_MAIL_FROM_DSP_HI))
|
||||
{
|
||||
DEBUG_LOG(DSPINTERFACE, "DSPInterface(r16) 0x%08x (0x%04x) (%08x)", _iAddress, _uReturnValue, PowerPC::ppcState.pc);
|
||||
}
|
||||
}
|
||||
|
||||
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::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;
|
||||
|
||||
// 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:
|
||||
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;
|
||||
// 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();
|
||||
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;
|
||||
// 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;
|
||||
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;
|
||||
// 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>()
|
||||
);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue