From 1276241622795c8f7ec74d66b615cdb2dca22cfc Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Tue, 24 Sep 2019 23:44:38 +1000 Subject: [PATCH] SPU: Create stub needed for DMA to work --- src/pse/bus.cpp | 36 ++++++----- src/pse/bus.h | 12 ++-- src/pse/bus.inl | 4 +- src/pse/dma.cpp | 15 ++++- src/pse/dma.h | 5 +- src/pse/pse.vcxproj | 2 + src/pse/pse.vcxproj.filters | 2 + src/pse/spu.cpp | 121 ++++++++++++++++++++++++++++++++++++ src/pse/spu.h | 97 +++++++++++++++++++++++++++++ src/pse/system.cpp | 15 ++++- src/pse/system.h | 2 + 11 files changed, 283 insertions(+), 28 deletions(-) create mode 100644 src/pse/spu.cpp create mode 100644 src/pse/spu.h diff --git a/src/pse/bus.cpp b/src/pse/bus.cpp index 681bec821..97b140649 100644 --- a/src/pse/bus.cpp +++ b/src/pse/bus.cpp @@ -10,6 +10,7 @@ #include "gpu.h" #include "interrupt_controller.h" #include "pad.h" +#include "spu.h" #include "timers.h" #include Log_SetChannel(Bus); @@ -27,7 +28,7 @@ Bus::Bus() = default; Bus::~Bus() = default; bool Bus::Initialize(CPU::Core* cpu, DMA* dma, InterruptController* interrupt_controller, GPU* gpu, CDROM* cdrom, - Pad* pad, Timers* timers) + Pad* pad, Timers* timers, SPU* spu) { if (!LoadBIOS()) return false; @@ -39,6 +40,7 @@ bool Bus::Initialize(CPU::Core* cpu, DMA* dma, InterruptController* interrupt_co m_cdrom = cdrom; m_pad = pad; m_timers = timers; + m_spu = spu; return true; } @@ -354,30 +356,34 @@ bool Bus::DoWriteTimers(MemoryAccessSize size, u32 offset, u32 value) return true; } -bool Bus::ReadSPU(MemoryAccessSize size, u32 offset, u32& value) +bool Bus::DoReadSPU(MemoryAccessSize size, u32 offset, u32& value) { - if (offset == 0x1AE) + // 32-bit reads are read as two 16-bit writes. + if (size == MemoryAccessSize::Word) { - value = 0; - return true; + const u16 lsb = m_spu->ReadRegister(offset); + const u16 msb = m_spu->ReadRegister(offset + 2); + value = ZeroExtend32(lsb) | (ZeroExtend32(msb) << 16); + } + else + { + value = ZeroExtend32(m_spu->ReadRegister(offset)); } - // return DoInvalidAccess(MemoryAccessType::Write, size, SPU_BASE | offset, SPU_BASE | offset, value); - value = 0; return true; } -bool Bus::WriteSPU(MemoryAccessSize size, u32 offset, u32 value) +bool Bus::DoWriteSPU(MemoryAccessSize size, u32 offset, u32 value) { - // Transfer FIFO - if (offset == 0x1A8) + // 32-bit writes are written as two 16-bit writes. + if (size == MemoryAccessSize::Word) + { + m_spu->WriteRegister(offset, Truncate16(value)); + m_spu->WriteRegister(offset + 2, Truncate16(value >> 16)); return true; + } - // SPUCNT - if (offset == 0x1AA) - return true; - - // return DoInvalidAccess(MemoryAccessType::Write, size, SPU_BASE | offset, SPU_BASE | offset, value); + m_spu->WriteRegister(offset, Truncate16(value)); return true; } diff --git a/src/pse/bus.h b/src/pse/bus.h index 1a27e1eb0..9fed1a64c 100644 --- a/src/pse/bus.h +++ b/src/pse/bus.h @@ -6,8 +6,7 @@ class StateWrapper; -namespace CPU -{ +namespace CPU { class Core; } @@ -17,6 +16,7 @@ class GPU; class CDROM; class Pad; class Timers; +class SPU; class System; class Bus @@ -25,7 +25,8 @@ public: Bus(); ~Bus(); - bool Initialize(CPU::Core* cpu, DMA* dma, InterruptController* interrupt_controller, GPU* gpu, CDROM* cdrom, Pad* pad, Timers* timers); + bool Initialize(CPU::Core* cpu, DMA* dma, InterruptController* interrupt_controller, GPU* gpu, CDROM* cdrom, Pad* pad, + Timers* timers, SPU* spu); void Reset(); bool DoState(StateWrapper& sw); @@ -114,8 +115,8 @@ private: bool DoReadTimers(MemoryAccessSize size, u32 offset, u32& value); bool DoWriteTimers(MemoryAccessSize size, u32 offset, u32 value); - bool ReadSPU(MemoryAccessSize size, u32 offset, u32& value); - bool WriteSPU(MemoryAccessSize size, u32 offset, u32 value); + bool DoReadSPU(MemoryAccessSize size, u32 offset, u32& value); + bool DoWriteSPU(MemoryAccessSize size, u32 offset, u32 value); CPU::Core* m_cpu = nullptr; DMA* m_dma = nullptr; @@ -124,6 +125,7 @@ private: CDROM* m_cdrom = nullptr; Pad* m_pad = nullptr; Timers* m_timers = nullptr; + SPU* m_spu = nullptr; std::array m_ram{}; // 2MB RAM std::array m_bios{}; // 512K BIOS ROM diff --git a/src/pse/bus.inl b/src/pse/bus.inl index 46470c2a5..885bd92f8 100644 --- a/src/pse/bus.inl +++ b/src/pse/bus.inl @@ -155,8 +155,8 @@ bool Bus::DispatchAccess(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddres } else if (bus_address < (SPU_BASE + SPU_SIZE)) { - return (type == MemoryAccessType::Read) ? ReadSPU(size, bus_address & SPU_MASK, value) : - WriteSPU(size, bus_address & SPU_MASK, value); + return (type == MemoryAccessType::Read) ? DoReadSPU(size, bus_address & SPU_MASK, value) : + DoWriteSPU(size, bus_address & SPU_MASK, value); } else if (bus_address < EXP2_BASE) { diff --git a/src/pse/dma.cpp b/src/pse/dma.cpp index 941d3de12..a9ad5a302 100644 --- a/src/pse/dma.cpp +++ b/src/pse/dma.cpp @@ -5,6 +5,7 @@ #include "common/state_wrapper.h" #include "gpu.h" #include "interrupt_controller.h" +#include "spu.h" #include "system.h" Log_SetChannel(DMA); @@ -12,13 +13,15 @@ DMA::DMA() = default; DMA::~DMA() = default; -bool DMA::Initialize(System* system, Bus* bus, InterruptController* interrupt_controller, GPU* gpu, CDROM* cdrom) +bool DMA::Initialize(System* system, Bus* bus, InterruptController* interrupt_controller, GPU* gpu, CDROM* cdrom, + SPU* spu) { m_system = system; m_bus = bus; m_interrupt_controller = interrupt_controller; m_gpu = gpu; m_cdrom = cdrom; + m_spu = spu; return true; } @@ -79,6 +82,7 @@ u32 DMA::ReadRegister(u32 offset) void DMA::WriteRegister(u32 offset, u32 value) { const u32 channel_index = offset >> 4; + Log_DevPrintf("DMA channel %u offset %u", channel_index, offset); if (channel_index < 7) { ChannelState& state = m_state[channel_index]; @@ -370,9 +374,11 @@ u32 DMA::DMARead(Channel channel, PhysicalMemoryAddress dst_address, u32 remaini case Channel::CDROM: return m_cdrom->DMARead(); + case Channel::SPU: + return m_spu->DMARead(); + case Channel::MDECin: case Channel::MDECout: - case Channel::SPU: case Channel::PIO: default: Panic("Unhandled DMA channel read"); @@ -388,10 +394,13 @@ void DMA::DMAWrite(Channel channel, u32 value, PhysicalMemoryAddress src_address m_gpu->DMAWrite(value); return; + case Channel::SPU: + m_spu->DMAWrite(value); + break; + case Channel::MDECin: case Channel::MDECout: case Channel::CDROM: - case Channel::SPU: case Channel::PIO: case Channel::OTC: default: diff --git a/src/pse/dma.h b/src/pse/dma.h index 23a35a659..69ba6c08a 100644 --- a/src/pse/dma.h +++ b/src/pse/dma.h @@ -10,6 +10,7 @@ class Bus; class InterruptController; class GPU; class CDROM; +class SPU; class DMA { @@ -33,7 +34,8 @@ public: DMA(); ~DMA(); - bool Initialize(System* system, Bus* bus, InterruptController* interrupt_controller, GPU* gpu, CDROM* cdrom); + bool Initialize(System* system, Bus* bus, InterruptController* interrupt_controller, GPU* gpu, CDROM* cdrom, + SPU* spu); void Reset(); bool DoState(StateWrapper& sw); @@ -75,6 +77,7 @@ private: InterruptController* m_interrupt_controller = nullptr; GPU* m_gpu = nullptr; CDROM* m_cdrom = nullptr; + SPU* m_spu = nullptr; TickCount m_transfer_ticks = 0; bool m_transfer_pending = false; diff --git a/src/pse/pse.vcxproj b/src/pse/pse.vcxproj index 4e81aed10..d2d7adbab 100644 --- a/src/pse/pse.vcxproj +++ b/src/pse/pse.vcxproj @@ -49,6 +49,7 @@ + @@ -70,6 +71,7 @@ + diff --git a/src/pse/pse.vcxproj.filters b/src/pse/pse.vcxproj.filters index 667224c26..58b3f16b3 100644 --- a/src/pse/pse.vcxproj.filters +++ b/src/pse/pse.vcxproj.filters @@ -17,6 +17,7 @@ + @@ -39,6 +40,7 @@ + diff --git a/src/pse/spu.cpp b/src/pse/spu.cpp new file mode 100644 index 000000000..c8aa7dbbf --- /dev/null +++ b/src/pse/spu.cpp @@ -0,0 +1,121 @@ +#include "spu.h" +#include "YBaseLib/Log.h" +#include "common/state_wrapper.h" +#include "dma.h" +#include "interrupt_controller.h" +#include "system.h" +Log_SetChannel(SPU); + +SPU::SPU() = default; + +SPU::~SPU() = default; + +bool SPU::Initialize(System* system, DMA* dma, InterruptController* interrupt_controller) +{ + m_system = system; + m_dma = dma; + m_interrupt_controller = interrupt_controller; + return true; +} + +void SPU::Reset() +{ + m_SPUCNT.bits = 0; + m_SPUSTAT.bits = 0; + m_transfer_address = 0; + m_transfer_address_reg = 0; +} + +bool SPU::DoState(StateWrapper& sw) +{ + sw.Do(&m_SPUCNT.bits); + sw.Do(&m_SPUSTAT.bits); + sw.Do(&m_transfer_address); + sw.Do(&m_transfer_address_reg); + return !sw.HasError(); +} + +u16 SPU::ReadRegister(u32 offset) +{ + switch (offset) + { + case 0x1F801DA6 - SPU_BASE: + Log_DebugPrintf("SPU transfer address register -> 0x%04X", ZeroExtend32(m_transfer_address_reg)); + return m_transfer_address_reg; + + case 0x1F801DA8 - SPU_BASE: + Log_ErrorPrintf("SPU transfer data register read"); + return UINT16_C(0xFFFF); + + case 0x1F801DAA - SPU_BASE: + Log_DebugPrintf("SPU control register -> 0x%04X", ZeroExtend32(m_SPUCNT.bits)); + return m_SPUCNT.bits; + + case 0x1F801DAE - SPU_BASE: + Log_DebugPrintf("SPU status register -> 0x%04X", ZeroExtend32(m_SPUCNT.bits)); + return m_SPUSTAT.bits; + + default: + Log_ErrorPrintf("Unknown SPU register read: offset 0x%X (address 0x%08X)", offset, offset | SPU_BASE); + return UINT16_C(0xFFFF); + } +} + +void SPU::WriteRegister(u32 offset, u16 value) +{ + switch (offset) + { + case 0x1F801DA6 - SPU_BASE: + { + Log_DebugPrintf("SPU transfer address register <- 0x%04X", ZeroExtend32(value)); + m_transfer_address_reg = value; + m_transfer_address = ZeroExtend32(value) * 8; + return; + } + + case 0x1F801DA8 - SPU_BASE: + { + std::memcpy(&m_ram[m_transfer_address], &value, sizeof(value)); + Log_TracePrintf("SPU transfer data register <- 0x%04X (RAM offset 0x%08X)", ZeroExtend32(value), + m_transfer_address); + m_transfer_address = (m_transfer_address + sizeof(value)) & RAM_MASK; + return; + } + + case 0x1F801DAA - SPU_BASE: + { + Log_DebugPrintf("SPU control register <- 0x%04X", ZeroExtend32(value)); + m_SPUCNT.bits = value; + UpdateDMARequest(); + return; + } + + // read-only registers + case 0x1F801DAE - SPU_BASE: + { + return; + } + + default: + { + Log_ErrorPrintf("Unknown SPU register write: offset 0x%X (address 0x%08X) value 0x%04X", offset, + offset | SPU_BASE, ZeroExtend32(value)); + return; + } + } +} + +u32 SPU::DMARead() +{ + Log_ErrorPrintf("SPU DMA READ"); + return UINT32_C(0xFFFFFFFF); +} + +void SPU::DMAWrite(u32 value) {} + +void SPU::UpdateDMARequest() +{ + const RAMTransferMode mode = m_SPUCNT.ram_transfer_mode; + const bool request = (mode == RAMTransferMode::DMAWrite || mode == RAMTransferMode::DMARead); + m_dma->SetRequest(DMA::Channel::SPU, request); +} diff --git a/src/pse/spu.h b/src/pse/spu.h new file mode 100644 index 000000000..e61849669 --- /dev/null +++ b/src/pse/spu.h @@ -0,0 +1,97 @@ +#pragma once +#include "common/bitfield.h" +#include "types.h" +#include + +class StateWrapper; + +class System; +class DMA; +class InterruptController; + +class SPU +{ +public: + SPU(); + ~SPU(); + + bool Initialize(System* system, DMA* dma, InterruptController* interrupt_controller); + void Reset(); + bool DoState(StateWrapper& sw); + + u16 ReadRegister(u32 offset); + void WriteRegister(u32 offset, u16 value); + + u32 DMARead(); + void DMAWrite(u32 value); + +private: + static constexpr u32 RAM_SIZE = 512 * 1024; + static constexpr u32 RAM_MASK = RAM_SIZE - 1; + static constexpr u32 SPU_BASE = 0x1F801C00; + + enum class RAMTransferMode : u8 + { + Stopped =0, + ManualWrite = 1, + DMAWrite = 2, + DMARead = 3 + }; + + union SPUCNT + { + u16 bits; + + BitField enable; + BitField mute; + BitField noise_frequency_shift; + BitField noise_frequency_step; + BitField reverb_master_enable; + BitField irq9_enable; + BitField ram_transfer_mode; + BitField external_audio_reverb; + BitField cd_audio_reverb; + BitField external_audio_enable; + BitField cd_audio_enable; + + BitField mode; + }; + + union SPUSTAT + { + u16 bits; + + BitField second_half_capture_buffer; + BitField transfer_busy; + BitField dma_read_request; + BitField dma_write_request; + BitField dma_read_write_request; + BitField irq9_flag; + BitField mode; + }; + +#if 0 + struct Voice + { + static constexpr u32 NUM_REGS = 8; + static constexpr u32 NUM_FLAGS = 6; + + std::array regs; + + }; +#endif + + void UpdateDMARequest(); + + System* m_system = nullptr; + DMA* m_dma = nullptr; + InterruptController* m_interrupt_controller = nullptr; + + SPUCNT m_SPUCNT = {}; + SPUSTAT m_SPUSTAT = {}; + + u16 m_transfer_address_reg = 0; + u32 m_transfer_address = 0; + + std::array m_ram{}; +}; \ No newline at end of file diff --git a/src/pse/system.cpp b/src/pse/system.cpp index a9fb11839..2b9f2bfd4 100644 --- a/src/pse/system.cpp +++ b/src/pse/system.cpp @@ -9,6 +9,7 @@ #include "interrupt_controller.h" #include "pad.h" #include "pad_device.h" +#include "spu.h" #include "timers.h" #include Log_SetChannel(System); @@ -24,6 +25,7 @@ System::System(HostInterface* host_interface) : m_host_interface(host_interface) m_cdrom = std::make_unique(); m_pad = std::make_unique(); m_timers = std::make_unique(); + m_spu = std::make_unique(); } System::~System() = default; @@ -34,13 +36,15 @@ bool System::Initialize() return false; if (!m_bus->Initialize(m_cpu.get(), m_dma.get(), m_interrupt_controller.get(), m_gpu.get(), m_cdrom.get(), - m_pad.get(), m_timers.get())) + m_pad.get(), m_timers.get(), m_spu.get())) { return false; } - if (!m_dma->Initialize(this, m_bus.get(), m_interrupt_controller.get(), m_gpu.get(), m_cdrom.get())) + if (!m_dma->Initialize(this, m_bus.get(), m_interrupt_controller.get(), m_gpu.get(), m_cdrom.get(), m_spu.get())) + { return false; + } if (!m_interrupt_controller->Initialize(m_cpu.get())) return false; @@ -57,6 +61,9 @@ bool System::Initialize() if (!m_timers->Initialize(this, m_interrupt_controller.get())) return false; + if (!m_spu->Initialize(this, m_dma.get(), m_interrupt_controller.get())) + return false; + return true; } @@ -86,6 +93,9 @@ bool System::DoState(StateWrapper& sw) if (!sw.DoMarker("Timers") || !m_timers->DoState(sw)) return false; + if (!sw.DoMarker("SPU") || !m_timers->DoState(sw)) + return false; + return !sw.HasError(); } @@ -99,6 +109,7 @@ void System::Reset() m_cdrom->Reset(); m_pad->Reset(); m_timers->Reset(); + m_spu->Reset(); m_frame_number = 1; } diff --git a/src/pse/system.h b/src/pse/system.h index b073c3315..560ad2444 100644 --- a/src/pse/system.h +++ b/src/pse/system.h @@ -20,6 +20,7 @@ class CDROM; class Pad; class PadDevice; class Timers; +class SPU; class System { @@ -64,5 +65,6 @@ private: std::unique_ptr m_cdrom; std::unique_ptr m_pad; std::unique_ptr m_timers; + std::unique_ptr m_spu; u32 m_frame_number = 1; };