From b951f27381a2d3a7a093f27202acc54ae309b1d5 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Tue, 17 Sep 2019 19:22:39 +1000 Subject: [PATCH] CDROM: Stub implementation --- src/pse/bus.cpp | 20 +++- src/pse/bus.h | 18 +++- src/pse/bus.inl | 9 ++ src/pse/cdrom.cpp | 199 +++++++++++++++++++++++++++++++++++- src/pse/cdrom.h | 66 ++++++++++++ src/pse/pse.vcxproj | 2 + src/pse/pse.vcxproj.filters | 2 + src/pse/system.cpp | 11 +- src/pse/system.h | 2 + 9 files changed, 321 insertions(+), 8 deletions(-) create mode 100644 src/pse/cdrom.h diff --git a/src/pse/bus.cpp b/src/pse/bus.cpp index 04076193d..df32d98fb 100644 --- a/src/pse/bus.cpp +++ b/src/pse/bus.cpp @@ -2,6 +2,7 @@ #include "YBaseLib/ByteStream.h" #include "YBaseLib/Log.h" #include "YBaseLib/String.h" +#include "cdrom.h" #include "common/state_wrapper.h" #include "cpu_core.h" #include "cpu_disasm.h" @@ -23,7 +24,7 @@ Bus::Bus() = default; Bus::~Bus() = default; -bool Bus::Initialize(CPU::Core* cpu, DMA* dma, InterruptController* interrupt_controller, GPU* gpu) +bool Bus::Initialize(CPU::Core* cpu, DMA* dma, InterruptController* interrupt_controller, GPU* gpu, CDROM* cdrom) { if (!LoadBIOS()) return false; @@ -32,6 +33,7 @@ bool Bus::Initialize(CPU::Core* cpu, DMA* dma, InterruptController* interrupt_co m_dma = dma; m_interrupt_controller = interrupt_controller; m_gpu = gpu; + m_cdrom = cdrom; return true; } @@ -214,6 +216,22 @@ bool Bus::WriteExpansionRegion2(MemoryAccessSize size, u32 offset, u32 value) return DoInvalidAccess(MemoryAccessType::Write, size, EXP2_BASE | offset, EXP2_BASE | offset, value); } +bool Bus::DoReadCDROM(MemoryAccessSize size, u32 offset, u32& value) +{ + // TODO: Splitting of half/word reads. + Assert(size == MemoryAccessSize::Byte); + value = ZeroExtend32(m_cdrom->ReadRegister(offset)); + return true; +} + +bool Bus::DoWriteCDROM(MemoryAccessSize size, u32 offset, u32 value) +{ + // TODO: Splitting of half/word reads. + Assert(size == MemoryAccessSize::Byte); + m_cdrom->WriteRegister(offset, Truncate8(value)); + return true; +} + bool Bus::DoReadGPU(MemoryAccessSize size, u32 offset, u32& value) { Assert(size == MemoryAccessSize::Word); diff --git a/src/pse/bus.h b/src/pse/bus.h index 0ed9879ca..22c5d541d 100644 --- a/src/pse/bus.h +++ b/src/pse/bus.h @@ -12,8 +12,9 @@ class Core; } class DMA; -class GPU; class InterruptController; +class GPU; +class CDROM; class System; class Bus @@ -22,7 +23,7 @@ public: Bus(); ~Bus(); - bool Initialize(CPU::Core* cpu, DMA* dma, InterruptController* interrupt_controller, GPU* gpu); + bool Initialize(CPU::Core* cpu, DMA* dma, InterruptController* interrupt_controller, GPU* gpu, CDROM* cdrom); void Reset(); bool DoState(StateWrapper& sw); @@ -39,15 +40,18 @@ public: void PatchBIOS(u32 address, u32 value, u32 mask = UINT32_C(0xFFFFFFFF)); private: - static constexpr u32 GPU_BASE = 0x1F801810; - static constexpr u32 GPU_SIZE = 0x10; - static constexpr u32 GPU_MASK = GPU_SIZE - 1; static constexpr u32 INTERRUPT_CONTROLLER_BASE = 0x1F801070; static constexpr u32 INTERRUPT_CONTROLLER_SIZE = 0x08; static constexpr u32 INTERRUPT_CONTROLLER_MASK = INTERRUPT_CONTROLLER_SIZE - 1; static constexpr u32 DMA_BASE = 0x1F801080; static constexpr u32 DMA_SIZE = 0x80; static constexpr u32 DMA_MASK = DMA_SIZE - 1; + static constexpr u32 CDROM_BASE = 0x1F801800; + static constexpr u32 CDROM_SIZE = 0x04; + static constexpr u32 CDROM_MASK = CDROM_SIZE - 1; + static constexpr u32 GPU_BASE = 0x1F801810; + static constexpr u32 GPU_SIZE = 0x10; + static constexpr u32 GPU_MASK = GPU_SIZE - 1; static constexpr u32 SPU_BASE = 0x1F801C00; static constexpr u32 SPU_SIZE = 0x300; static constexpr u32 SPU_MASK = 0x3FF; @@ -71,6 +75,9 @@ private: bool ReadExpansionRegion2(MemoryAccessSize size, u32 offset, u32& value); bool WriteExpansionRegion2(MemoryAccessSize size, u32 offset, u32 value); + bool DoReadCDROM(MemoryAccessSize size, u32 offset, u32& value); + bool DoWriteCDROM(MemoryAccessSize size, u32 offset, u32 value); + bool DoReadGPU(MemoryAccessSize size, u32 offset, u32& value); bool DoWriteGPU(MemoryAccessSize size, u32 offset, u32 value); @@ -87,6 +94,7 @@ private: DMA* m_dma = nullptr; InterruptController* m_interrupt_controller = nullptr; GPU* m_gpu = nullptr; + CDROM* m_cdrom = 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 b89190642..bbbbd187f 100644 --- a/src/pse/bus.inl +++ b/src/pse/bus.inl @@ -99,6 +99,15 @@ bool Bus::DispatchAccess(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddres return (type == MemoryAccessType::Read) ? DoReadDMA(size, bus_address & DMA_MASK, value) : DoWriteDMA(size, bus_address & DMA_MASK, value); } + else if (bus_address < CDROM_BASE) + { + return DoInvalidAccess(type, size, cpu_address, bus_address, value); + } + else if (bus_address < (CDROM_BASE + GPU_SIZE)) + { + return (type == MemoryAccessType::Read) ? DoReadCDROM(size, bus_address & CDROM_MASK, value) : + DoWriteCDROM(size, bus_address & CDROM_MASK, value); + } else if (bus_address < GPU_BASE) { return DoInvalidAccess(type, size, cpu_address, bus_address, value); diff --git a/src/pse/cdrom.cpp b/src/pse/cdrom.cpp index 37dfada43..18920f423 100644 --- a/src/pse/cdrom.cpp +++ b/src/pse/cdrom.cpp @@ -1 +1,198 @@ -#include "interrupt_controller.h" \ No newline at end of file +#include "cdrom.h" +#include "YBaseLib/Log.h" +#include "common/state_wrapper.h" +Log_SetChannel(CDROM); + +CDROM::CDROM() = default; + +CDROM::~CDROM() = default; + +bool CDROM::Initialize(DMA* dma, InterruptController* interrupt_controller) +{ + m_dma = dma; + m_interrupt_controller = interrupt_controller; + return true; +} + +void CDROM::Reset() +{ + m_param_fifo.Clear(); + m_response_fifo.Clear(); + m_data_fifo.Clear(); +} + +bool CDROM::DoState(StateWrapper& sw) +{ + sw.Do(&m_state); + sw.Do(&m_status.bits); + sw.Do(&m_param_fifo); + sw.Do(&m_response_fifo); + sw.Do(&m_data_fifo); + return !sw.HasError(); +} + +u8 CDROM::ReadRegister(u32 offset) +{ + switch (offset) + { + case 0: // status register + return m_status.bits; + + case 1: // always response FIFO + return m_response_fifo.Pop(); + + case 2: // always data FIFO + return m_data_fifo.Pop(); + + case 3: + { + switch (m_status.index) + { + case 0: + case 2: + return m_interrupt_enable_register | ~INTERRUPT_REGISTER_MASK; + + case 1: + case 3: + return m_interrupt_flag_register; + } + } + break; + } + + Log_ErrorPrintf("Unknown CDROM register read: offset=0x%02X, index=%d", offset, + ZeroExtend32(m_status.index.GetValue())); + Panic("Unknown CDROM register"); + return 0; +} + +void CDROM::WriteRegister(u32 offset, u8 value) +{ + switch (offset) + { + case 0: + { + Log_DebugPrintf("CDROM status register <- 0x%02X", ZeroExtend32(value)); + m_status.bits = (m_status.bits & static_cast(~3)) | (value & u8(3)); + return; + } + break; + + case 1: + { + switch (m_status.index) + { + case 0: + { + Log_DebugPrintf("CDROM command register <- 0x%02X", ZeroExtend32(value)); + if (m_state != State::Idle) + Log_ErrorPrintf("Ignoring write (0x%02X) to command register in non-idle state", ZeroExtend32(value)); + else + WriteCommand(value); + + return; + } + + case 1: + { + Log_ErrorPrintf("Sound map data out <- 0x%02X", ZeroExtend32(value)); + return; + } + + case 2: + { + Log_ErrorPrintf("Sound map coding info <- 0x%02X", ZeroExtend32(value)); + return; + } + + case 3: + { + Log_ErrorPrintf("Audio volume for right-to-left output <- 0x%02X", ZeroExtend32(value)); + return; + } + } + } + break; + + case 2: + { + switch (m_status.index) + { + case 0: + { + if (m_param_fifo.IsFull()) + { + Log_WarningPrintf("Parameter FIFO overflow"); + m_param_fifo.RemoveOne(); + } + + m_param_fifo.Push(value); + return; + } + + case 1: + { + Log_DebugPrintf("Interrupt enable register <- 0x%02X", ZeroExtend32(value)); + m_interrupt_enable_register = value & INTERRUPT_REGISTER_MASK; + return; + } + + case 2: + { + Log_ErrorPrintf("Audio volume for left-to-left output <- 0x%02X", ZeroExtend32(value)); + return; + } + + case 3: + { + Log_ErrorPrintf("Audio volume for right-to-left output <- 0x%02X", ZeroExtend32(value)); + return; + } + } + } + break; + + case 3: + { + switch (m_status.index) + { + case 0: + { + Log_ErrorPrintf("Request register <- 0x%02X", value); + return; + } + + case 1: + { + Log_DebugPrintf("Interrupt flag register <- 0x%02X", value); + m_interrupt_flag_register &= ~(value & INTERRUPT_REGISTER_MASK); + Execute(); + return; + } + + case 2: + { + Log_ErrorPrintf("Audio volume for left-to-right output <- 0x%02X", ZeroExtend32(value)); + return; + } + + case 3: + { + Log_ErrorPrintf("Audio volume apply changes <- 0x%02X", ZeroExtend32(value)); + return; + } + } + } + break; + } + + Log_ErrorPrintf("Unknown CDROM register write: offset=0x%02X, index=%d, value=0x%02X", offset, + ZeroExtend32(m_status.index.GetValue()), ZeroExtend32(value)); +} + +void CDROM::Execute() {} + +void CDROM::WriteCommand(u8 command) +{ + Log_ErrorPrintf("CDROM write command 0x%02X", ZeroExtend32(command)); +} diff --git a/src/pse/cdrom.h b/src/pse/cdrom.h new file mode 100644 index 000000000..adc30d1b6 --- /dev/null +++ b/src/pse/cdrom.h @@ -0,0 +1,66 @@ +#pragma once +#include "types.h" +#include "common/bitfield.h" +#include "common/fifo_queue.h" + +class StateWrapper; + +class DMA; +class InterruptController; + +class CDROM +{ +public: + CDROM(); + ~CDROM(); + + bool Initialize(DMA* dma, InterruptController* interrupt_controller); + void Reset(); + bool DoState(StateWrapper& sw); + + // I/O + u8 ReadRegister(u32 offset); + void WriteRegister(u32 offset, u8 value); + + void Execute(); + +private: + static constexpr u32 PARAM_FIFO_SIZE = 16; + static constexpr u32 RESPONSE_FIFO_SIZE = 16; + static constexpr u32 DATA_FIFO_SIZE = 4096; + static constexpr u32 NUM_INTERRUPTS = 32; + static constexpr u8 INTERRUPT_REGISTER_MASK = 0x1F; + + bool HasPendingInterrupt() const { return m_interrupt_flag_register != 0; } + void WriteCommand(u8 command); + + DMA* m_dma; + InterruptController* m_interrupt_controller; + + enum class State : u32 + { + Idle + }; + + State m_state = State::Idle; + + union + { + u8 bits; + BitField index; + BitField ADPBUSY; + BitField PRMEMPTY; + BitField PRMWRDY; + BitField RSLRRDY; + BitField DRQSTS; + BitField BUSYSTS; + } m_status = {}; + + u8 m_interrupt_enable_register = INTERRUPT_REGISTER_MASK; + u8 m_interrupt_flag_register = 0; + + InlineFIFOQueue m_param_fifo; + InlineFIFOQueue m_response_fifo; + HeapFIFOQueue m_data_fifo; +}; + diff --git a/src/pse/pse.vcxproj b/src/pse/pse.vcxproj index dfa89cd29..e553f727e 100644 --- a/src/pse/pse.vcxproj +++ b/src/pse/pse.vcxproj @@ -36,6 +36,7 @@ + @@ -48,6 +49,7 @@ + diff --git a/src/pse/pse.vcxproj.filters b/src/pse/pse.vcxproj.filters index 1aa24e9b2..c72d24162 100644 --- a/src/pse/pse.vcxproj.filters +++ b/src/pse/pse.vcxproj.filters @@ -11,6 +11,7 @@ + @@ -26,6 +27,7 @@ + diff --git a/src/pse/system.cpp b/src/pse/system.cpp index 9e67f3cde..9ce65542a 100644 --- a/src/pse/system.cpp +++ b/src/pse/system.cpp @@ -6,6 +6,7 @@ #include "dma.h" #include "gpu.h" #include "interrupt_controller.h" +#include "cdrom.h" System::System(HostInterface* host_interface) : m_host_interface(host_interface) { @@ -15,6 +16,7 @@ System::System(HostInterface* host_interface) : m_host_interface(host_interface) m_interrupt_controller = std::make_unique(); // m_gpu = std::make_unique(); m_gpu = GPU::CreateHardwareOpenGLRenderer(); + m_cdrom = std::make_unique(); } System::~System() = default; @@ -24,7 +26,7 @@ bool System::Initialize() if (!m_cpu->Initialize(m_bus.get())) return false; - if (!m_bus->Initialize(m_cpu.get(), m_dma.get(), m_interrupt_controller.get(), m_gpu.get())) + if (!m_bus->Initialize(m_cpu.get(), m_dma.get(), m_interrupt_controller.get(), m_gpu.get(), m_cdrom.get())) return false; if (!m_dma->Initialize(m_bus.get(), m_gpu.get())) @@ -36,6 +38,9 @@ bool System::Initialize() if (!m_gpu->Initialize(this, m_bus.get(), m_dma.get())) return false; + if (!m_cdrom->Initialize(m_dma.get(), m_interrupt_controller.get())) + return false; + return true; } @@ -56,6 +61,9 @@ bool System::DoState(StateWrapper& sw) if (!sw.DoMarker("GPU") || !m_gpu->DoState(sw)) return false; + if (!sw.DoMarker("CDROM") || !m_cdrom->DoState(sw)) + return false; + return !sw.HasError(); } @@ -68,6 +76,7 @@ void System::Reset() m_dma->Reset(); m_interrupt_controller->Reset(); m_gpu->Reset(); + m_cdrom->Reset(); m_frame_number = 1; } diff --git a/src/pse/system.h b/src/pse/system.h index c56e95750..3c1aefea0 100644 --- a/src/pse/system.h +++ b/src/pse/system.h @@ -15,6 +15,7 @@ class Bus; class DMA; class InterruptController; class GPU; +class CDROM; class System { @@ -48,5 +49,6 @@ private: std::unique_ptr m_dma; std::unique_ptr m_interrupt_controller; std::unique_ptr m_gpu; + std::unique_ptr m_cdrom; u32 m_frame_number = 1; };