SPU: Create stub needed for DMA to work
This commit is contained in:
parent
7a413b4031
commit
1276241622
|
@ -10,6 +10,7 @@
|
|||
#include "gpu.h"
|
||||
#include "interrupt_controller.h"
|
||||
#include "pad.h"
|
||||
#include "spu.h"
|
||||
#include "timers.h"
|
||||
#include <cstdio>
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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<u8, 2097152> m_ram{}; // 2MB RAM
|
||||
std::array<u8, 524288> m_bios{}; // 512K BIOS ROM
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
<ClCompile Include="interrupt_controller.cpp" />
|
||||
<ClCompile Include="pad.cpp" />
|
||||
<ClCompile Include="pad_device.cpp" />
|
||||
<ClCompile Include="spu.cpp" />
|
||||
<ClCompile Include="system.cpp" />
|
||||
<ClCompile Include="timers.cpp" />
|
||||
</ItemGroup>
|
||||
|
@ -70,6 +71,7 @@
|
|||
<ClInclude Include="pad.h" />
|
||||
<ClInclude Include="pad_device.h" />
|
||||
<ClInclude Include="save_state_version.h" />
|
||||
<ClInclude Include="spu.h" />
|
||||
<ClInclude Include="system.h" />
|
||||
<ClInclude Include="timers.h" />
|
||||
<ClInclude Include="types.h" />
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
<ClCompile Include="pad_device.cpp" />
|
||||
<ClCompile Include="digital_controller.cpp" />
|
||||
<ClCompile Include="timers.cpp" />
|
||||
<ClCompile Include="spu.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="types.h" />
|
||||
|
@ -39,6 +40,7 @@
|
|||
<ClInclude Include="pad_device.h" />
|
||||
<ClInclude Include="digital_controller.h" />
|
||||
<ClInclude Include="timers.h" />
|
||||
<ClInclude Include="spu.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="cpu_core.inl" />
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
#pragma once
|
||||
#include "common/bitfield.h"
|
||||
#include "types.h"
|
||||
#include <array>
|
||||
|
||||
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<u16, bool, 15, 1> enable;
|
||||
BitField<u16, bool, 14, 1> mute;
|
||||
BitField<u16, u8, 10, 4> noise_frequency_shift;
|
||||
BitField<u16, u8, 8, 2> noise_frequency_step;
|
||||
BitField<u16, bool, 7, 1> reverb_master_enable;
|
||||
BitField<u16, bool, 6, 1> irq9_enable;
|
||||
BitField<u16, RAMTransferMode, 4, 2> ram_transfer_mode;
|
||||
BitField<u16, bool, 3, 1> external_audio_reverb;
|
||||
BitField<u16, bool, 2, 1> cd_audio_reverb;
|
||||
BitField<u16, bool, 1, 1> external_audio_enable;
|
||||
BitField<u16, bool, 0, 1> cd_audio_enable;
|
||||
|
||||
BitField<u16, u8, 0, 6> mode;
|
||||
};
|
||||
|
||||
union SPUSTAT
|
||||
{
|
||||
u16 bits;
|
||||
|
||||
BitField<u16, bool, 11, 1> second_half_capture_buffer;
|
||||
BitField<u16, bool, 10, 1> transfer_busy;
|
||||
BitField<u16, bool, 9, 1> dma_read_request;
|
||||
BitField<u16, bool, 8, 1> dma_write_request;
|
||||
BitField<u16, bool, 7, 1> dma_read_write_request;
|
||||
BitField<u16, bool, 6, 1> irq9_flag;
|
||||
BitField<u16, u8, 0, 6> mode;
|
||||
};
|
||||
|
||||
#if 0
|
||||
struct Voice
|
||||
{
|
||||
static constexpr u32 NUM_REGS = 8;
|
||||
static constexpr u32 NUM_FLAGS = 6;
|
||||
|
||||
std::array<u16, NUM_REGS> 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<u8, RAM_SIZE> m_ram{};
|
||||
};
|
|
@ -9,6 +9,7 @@
|
|||
#include "interrupt_controller.h"
|
||||
#include "pad.h"
|
||||
#include "pad_device.h"
|
||||
#include "spu.h"
|
||||
#include "timers.h"
|
||||
#include <cstdio>
|
||||
Log_SetChannel(System);
|
||||
|
@ -24,6 +25,7 @@ System::System(HostInterface* host_interface) : m_host_interface(host_interface)
|
|||
m_cdrom = std::make_unique<CDROM>();
|
||||
m_pad = std::make_unique<Pad>();
|
||||
m_timers = std::make_unique<Timers>();
|
||||
m_spu = std::make_unique<SPU>();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ class CDROM;
|
|||
class Pad;
|
||||
class PadDevice;
|
||||
class Timers;
|
||||
class SPU;
|
||||
|
||||
class System
|
||||
{
|
||||
|
@ -64,5 +65,6 @@ private:
|
|||
std::unique_ptr<CDROM> m_cdrom;
|
||||
std::unique_ptr<Pad> m_pad;
|
||||
std::unique_ptr<Timers> m_timers;
|
||||
std::unique_ptr<SPU> m_spu;
|
||||
u32 m_frame_number = 1;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue