Partial implementation of DMA controller and GPU stubs
This commit is contained in:
parent
2149ab4d69
commit
27913cd20a
|
@ -3,6 +3,7 @@
|
||||||
#include "YBaseLib/Log.h"
|
#include "YBaseLib/Log.h"
|
||||||
#include "YBaseLib/String.h"
|
#include "YBaseLib/String.h"
|
||||||
#include "dma.h"
|
#include "dma.h"
|
||||||
|
#include "gpu.h"
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
Log_SetChannel(Bus);
|
Log_SetChannel(Bus);
|
||||||
|
|
||||||
|
@ -38,7 +39,7 @@ bool Bus::ReadByte(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Bus::ReadWord(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u16* value)
|
bool Bus::ReadHalfWord(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u16* value)
|
||||||
{
|
{
|
||||||
u32 temp = 0;
|
u32 temp = 0;
|
||||||
const bool result =
|
const bool result =
|
||||||
|
@ -47,7 +48,7 @@ bool Bus::ReadWord(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Bus::ReadDWord(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u32* value)
|
bool Bus::ReadWord(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u32* value)
|
||||||
{
|
{
|
||||||
return DispatchAccess<MemoryAccessType::Read, MemoryAccessSize::Word>(cpu_address, bus_address, *value);
|
return DispatchAccess<MemoryAccessType::Read, MemoryAccessSize::Word>(cpu_address, bus_address, *value);
|
||||||
}
|
}
|
||||||
|
@ -58,13 +59,13 @@ bool Bus::WriteByte(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus
|
||||||
return DispatchAccess<MemoryAccessType::Read, MemoryAccessSize::Byte>(cpu_address, bus_address, temp);
|
return DispatchAccess<MemoryAccessType::Read, MemoryAccessSize::Byte>(cpu_address, bus_address, temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Bus::WriteWord(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u16 value)
|
bool Bus::WriteHalfWord(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u16 value)
|
||||||
{
|
{
|
||||||
u32 temp = ZeroExtend32(value);
|
u32 temp = ZeroExtend32(value);
|
||||||
return DispatchAccess<MemoryAccessType::Read, MemoryAccessSize::HalfWord>(cpu_address, bus_address, temp);
|
return DispatchAccess<MemoryAccessType::Read, MemoryAccessSize::HalfWord>(cpu_address, bus_address, temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Bus::WriteDWord(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u32 value)
|
bool Bus::WriteWord(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u32 value)
|
||||||
{
|
{
|
||||||
return DispatchAccess<MemoryAccessType::Write, MemoryAccessSize::Word>(cpu_address, bus_address, value);
|
return DispatchAccess<MemoryAccessType::Write, MemoryAccessSize::Word>(cpu_address, bus_address, value);
|
||||||
}
|
}
|
||||||
|
@ -178,6 +179,20 @@ bool Bus::WriteExpansionRegion2(MemoryAccessSize size, u32 offset, u32 value)
|
||||||
return DoInvalidAccess(MemoryAccessType::Write, size, EXP2_BASE | offset, EXP2_BASE | offset, value);
|
return DoInvalidAccess(MemoryAccessType::Write, size, EXP2_BASE | offset, EXP2_BASE | offset, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Bus::DoReadGPU(MemoryAccessSize size, u32 offset, u32& value)
|
||||||
|
{
|
||||||
|
Assert(size == MemoryAccessSize::Word);
|
||||||
|
value = m_gpu->ReadRegister(offset);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Bus::DoWriteGPU(MemoryAccessSize size, u32 offset, u32 value)
|
||||||
|
{
|
||||||
|
Assert(size == MemoryAccessSize::Word);
|
||||||
|
m_gpu->WriteRegister(offset, value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool Bus::ReadSPU(MemoryAccessSize size, u32 offset, u32& value)
|
bool Bus::ReadSPU(MemoryAccessSize size, u32 offset, u32& value)
|
||||||
{
|
{
|
||||||
if (offset == 0x1AE)
|
if (offset == 0x1AE)
|
||||||
|
@ -186,7 +201,7 @@ bool Bus::ReadSPU(MemoryAccessSize size, u32 offset, u32& value)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//return DoInvalidAccess(MemoryAccessType::Write, size, SPU_BASE | offset, SPU_BASE | offset, value);
|
// return DoInvalidAccess(MemoryAccessType::Write, size, SPU_BASE | offset, SPU_BASE | offset, value);
|
||||||
value = 0;
|
value = 0;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -201,7 +216,7 @@ bool Bus::WriteSPU(MemoryAccessSize size, u32 offset, u32 value)
|
||||||
if (offset == 0x1AA)
|
if (offset == 0x1AA)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
//return DoInvalidAccess(MemoryAccessType::Write, size, SPU_BASE | offset, SPU_BASE | offset, value);
|
// return DoInvalidAccess(MemoryAccessType::Write, size, SPU_BASE | offset, SPU_BASE | offset, value);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,7 +227,7 @@ bool Bus::DoReadDMA(MemoryAccessSize size, u32 offset, u32& value)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Bus::DoWriteDMA(MemoryAccessSize size, u32 offset, u32& value)
|
bool Bus::DoWriteDMA(MemoryAccessSize size, u32 offset, u32 value)
|
||||||
{
|
{
|
||||||
Assert(size == MemoryAccessSize::Word);
|
Assert(size == MemoryAccessSize::Word);
|
||||||
m_dma->WriteRegister(offset, value);
|
m_dma->WriteRegister(offset, value);
|
||||||
|
|
|
@ -20,11 +20,11 @@ public:
|
||||||
bool DoState(StateWrapper& sw);
|
bool DoState(StateWrapper& sw);
|
||||||
|
|
||||||
bool ReadByte(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u8* value);
|
bool ReadByte(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u8* value);
|
||||||
bool ReadWord(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u16* value);
|
bool ReadHalfWord(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u16* value);
|
||||||
bool ReadDWord(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u32* value);
|
bool ReadWord(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u32* value);
|
||||||
bool WriteByte(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u8 value);
|
bool WriteByte(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u8 value);
|
||||||
bool WriteWord(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u16 value);
|
bool WriteHalfWord(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u16 value);
|
||||||
bool WriteDWord(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u32 value);
|
bool WriteWord(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u32 value);
|
||||||
|
|
||||||
template<MemoryAccessType type, MemoryAccessSize size>
|
template<MemoryAccessType type, MemoryAccessSize size>
|
||||||
bool DispatchAccess(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u32& value);
|
bool DispatchAccess(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u32& value);
|
||||||
|
@ -33,6 +33,9 @@ private:
|
||||||
static constexpr u32 DMA_BASE = 0x1F801080;
|
static constexpr u32 DMA_BASE = 0x1F801080;
|
||||||
static constexpr u32 DMA_SIZE = 0x80;
|
static constexpr u32 DMA_SIZE = 0x80;
|
||||||
static constexpr u32 DMA_MASK = DMA_SIZE - 1;
|
static constexpr u32 DMA_MASK = DMA_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_BASE = 0x1F801C00;
|
||||||
static constexpr u32 SPU_SIZE = 0x300;
|
static constexpr u32 SPU_SIZE = 0x300;
|
||||||
static constexpr u32 SPU_MASK = 0x3FF;
|
static constexpr u32 SPU_MASK = 0x3FF;
|
||||||
|
@ -54,11 +57,14 @@ private:
|
||||||
bool ReadExpansionRegion2(MemoryAccessSize size, u32 offset, u32& value);
|
bool ReadExpansionRegion2(MemoryAccessSize size, u32 offset, u32& value);
|
||||||
bool WriteExpansionRegion2(MemoryAccessSize size, u32 offset, u32 value);
|
bool WriteExpansionRegion2(MemoryAccessSize size, u32 offset, u32 value);
|
||||||
|
|
||||||
bool ReadSPU(MemoryAccessSize size, u32 offset, u32& value);
|
bool DoReadGPU(MemoryAccessSize size, u32 offset, u32& value);
|
||||||
bool WriteSPU(MemoryAccessSize size, u32 offset, u32 value);
|
bool DoWriteGPU(MemoryAccessSize size, u32 offset, u32 value);
|
||||||
|
|
||||||
bool DoReadDMA(MemoryAccessSize size, u32 offset, u32& value);
|
bool DoReadDMA(MemoryAccessSize size, u32 offset, u32& value);
|
||||||
bool DoWriteDMA(MemoryAccessSize size, u32 offset, u32& value);
|
bool DoWriteDMA(MemoryAccessSize size, u32 offset, u32 value);
|
||||||
|
|
||||||
|
bool ReadSPU(MemoryAccessSize size, u32 offset, u32& value);
|
||||||
|
bool WriteSPU(MemoryAccessSize size, u32 offset, u32 value);
|
||||||
|
|
||||||
DMA* m_dma = nullptr;
|
DMA* m_dma = nullptr;
|
||||||
GPU* m_gpu = nullptr;
|
GPU* m_gpu = nullptr;
|
||||||
|
|
|
@ -89,6 +89,15 @@ bool Bus::DispatchAccess(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddres
|
||||||
return (type == MemoryAccessType::Read) ? DoReadDMA(size, bus_address & DMA_MASK, value) :
|
return (type == MemoryAccessType::Read) ? DoReadDMA(size, bus_address & DMA_MASK, value) :
|
||||||
DoWriteDMA(size, bus_address & DMA_MASK, value);
|
DoWriteDMA(size, bus_address & DMA_MASK, value);
|
||||||
}
|
}
|
||||||
|
else if (bus_address < GPU_BASE)
|
||||||
|
{
|
||||||
|
return DoInvalidAccess(type, size, cpu_address, bus_address, value);
|
||||||
|
}
|
||||||
|
else if (bus_address < (GPU_BASE + GPU_SIZE))
|
||||||
|
{
|
||||||
|
return (type == MemoryAccessType::Read) ? DoReadGPU(size, bus_address & GPU_MASK, value) :
|
||||||
|
DoWriteGPU(size, bus_address & GPU_MASK, value);
|
||||||
|
}
|
||||||
else if (bus_address < SPU_BASE)
|
else if (bus_address < SPU_BASE)
|
||||||
{
|
{
|
||||||
return DoInvalidAccess(type, size, cpu_address, bus_address, value);
|
return DoInvalidAccess(type, size, cpu_address, bus_address, value);
|
||||||
|
|
|
@ -526,6 +526,32 @@ void Core::ExecuteInstruction(Instruction inst, u32 inst_pc)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case InstructionOp::lwl:
|
||||||
|
case InstructionOp::lwr:
|
||||||
|
{
|
||||||
|
const VirtualMemoryAddress addr = ReadReg(inst.i.rs) + inst.i.imm_sext32();
|
||||||
|
const VirtualMemoryAddress aligned_addr = addr & ~UINT32_C(3);
|
||||||
|
const u32 aligned_value = ReadMemoryWord(aligned_addr);
|
||||||
|
|
||||||
|
// note: bypasses load delay on the read
|
||||||
|
const u32 existing_value = m_regs.r[static_cast<u8>(inst.i.rt.GetValue())];
|
||||||
|
const u8 shift = (Truncate8(addr) & u8(3)) * u8(8);
|
||||||
|
u32 new_value;
|
||||||
|
if (inst.op == InstructionOp::lwl)
|
||||||
|
{
|
||||||
|
const u32 mask = UINT32_C(0x00FFFFFF) >> shift;
|
||||||
|
new_value = (existing_value & mask) | (aligned_value << (24 - shift));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const u32 mask = UINT32_C(0xFFFFFF00) << (24 - shift);
|
||||||
|
new_value = (existing_value & mask) | (aligned_value >> shift);
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteRegDelayed(inst.i.rt, new_value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case InstructionOp::sb:
|
case InstructionOp::sb:
|
||||||
{
|
{
|
||||||
const VirtualMemoryAddress addr = ReadReg(inst.i.rs) + inst.i.imm_sext32();
|
const VirtualMemoryAddress addr = ReadReg(inst.i.rs) + inst.i.imm_sext32();
|
||||||
|
@ -550,6 +576,31 @@ void Core::ExecuteInstruction(Instruction inst, u32 inst_pc)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case InstructionOp::swl:
|
||||||
|
case InstructionOp::swr:
|
||||||
|
{
|
||||||
|
const VirtualMemoryAddress addr = ReadReg(inst.i.rs) + inst.i.imm_sext32();
|
||||||
|
const VirtualMemoryAddress aligned_addr = addr & ~UINT32_C(3);
|
||||||
|
const u32 mem_value = ReadMemoryWord(aligned_addr);
|
||||||
|
const u32 reg_value = ReadReg(inst.i.rt);
|
||||||
|
const u8 shift = (Truncate8(addr) & u8(3)) * u8(8);
|
||||||
|
|
||||||
|
u32 new_value;
|
||||||
|
if (inst.op == InstructionOp::swl)
|
||||||
|
{
|
||||||
|
const u32 mem_mask = UINT32_C(0xFFFFFF00) << shift;
|
||||||
|
new_value = (mem_value & mem_mask) | (reg_value >> (24 - shift));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const u32 mem_mask = UINT32_C(0x00FFFFFF) >> (24 - shift);
|
||||||
|
new_value = (mem_value & mem_mask) | (reg_value << shift);
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteMemoryWord(aligned_addr, new_value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case InstructionOp::j:
|
case InstructionOp::j:
|
||||||
{
|
{
|
||||||
Branch((m_regs.pc & UINT32_C(0xF0000000)) | (inst.j.target << 2));
|
Branch((m_regs.pc & UINT32_C(0xF0000000)) | (inst.j.target << 2));
|
||||||
|
|
|
@ -61,19 +61,19 @@ static const std::array<const char*, 64> s_base_table = {{
|
||||||
"UNKNOWN", // 31
|
"UNKNOWN", // 31
|
||||||
"lb $rt, $offsetrs", // 32
|
"lb $rt, $offsetrs", // 32
|
||||||
"lh $rt, $offsetrs", // 33
|
"lh $rt, $offsetrs", // 33
|
||||||
"UNKNOWN", // 34
|
"lwl $rt, $offsetrs", // 34
|
||||||
"lw $rt, $offsetrs", // 35
|
"lw $rt, $offsetrs", // 35
|
||||||
"lbu $rt, $offsetrs", // 36
|
"lbu $rt, $offsetrs", // 36
|
||||||
"lhu $rt, $offsetrs", // 37
|
"lhu $rt, $offsetrs", // 37
|
||||||
"UNKNOWN", // 38
|
"lwr $rt, $offsetrs", // 38
|
||||||
"UNKNOWN", // 39
|
"UNKNOWN", // 39
|
||||||
"sb $rt, $offsetrs", // 40
|
"sb $rt, $offsetrs", // 40
|
||||||
"sh $rt, $offsetrs", // 41
|
"sh $rt, $offsetrs", // 41
|
||||||
"UNKNOWN", // 42
|
"swl $rt, $offsetrs", // 42
|
||||||
"sw $rt, $offsetrs", // 43
|
"sw $rt, $offsetrs", // 43
|
||||||
"UNKNOWN", // 44
|
"UNKNOWN", // 44
|
||||||
"UNKNOWN", // 45
|
"UNKNOWN", // 45
|
||||||
"UNKNOWN", // 46
|
"swr $rt, $offsetrs", // 46
|
||||||
"UNKNOWN", // 47
|
"UNKNOWN", // 47
|
||||||
"UNKNOWN", // 48
|
"UNKNOWN", // 48
|
||||||
"UNKNOWN", // 49
|
"UNKNOWN", // 49
|
||||||
|
|
157
src/pse/dma.cpp
157
src/pse/dma.cpp
|
@ -17,7 +17,7 @@ bool DMA::Initialize(Bus* bus, GPU* gpu)
|
||||||
void DMA::Reset()
|
void DMA::Reset()
|
||||||
{
|
{
|
||||||
m_state = {};
|
m_state = {};
|
||||||
m_DPCR.bits = 0;
|
m_DPCR.bits = 0x07654321;
|
||||||
m_DCIR = 0;
|
m_DCIR = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,5 +52,160 @@ u32 DMA::ReadRegister(u32 offset)
|
||||||
|
|
||||||
void DMA::WriteRegister(u32 offset, u32 value)
|
void DMA::WriteRegister(u32 offset, u32 value)
|
||||||
{
|
{
|
||||||
|
const u32 channel_index = offset >> 4;
|
||||||
|
if (channel_index < 7)
|
||||||
|
{
|
||||||
|
ChannelState& state = m_state[channel_index];
|
||||||
|
switch (offset & UINT32_C(0x0F))
|
||||||
|
{
|
||||||
|
case 0x00:
|
||||||
|
{
|
||||||
|
state.base_address = value & BASE_ADDRESS_MASK;
|
||||||
|
Log_DebugPrintf("DMA channel %u base address <- 0x%08X", channel_index, state.base_address);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case 0x04:
|
||||||
|
{
|
||||||
|
Log_DebugPrintf("DMA channel %u block control <- 0x%08X", channel_index, value);
|
||||||
|
state.block_control.bits = value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 0x08:
|
||||||
|
{
|
||||||
|
state.channel_control.bits = (state.channel_control.bits & ~ChannelState::ChannelControl::WRITE_MASK) |
|
||||||
|
(value & ChannelState::ChannelControl::WRITE_MASK);
|
||||||
|
Log_DebugPrintf("DMA channel %u channel control <- 0x%08X", channel_index, state.channel_control.bits);
|
||||||
|
if (CanRunChannel(static_cast<Channel>(channel_index)))
|
||||||
|
RunDMA(static_cast<Channel>(channel_index));
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (offset)
|
||||||
|
{
|
||||||
|
case 0x70:
|
||||||
|
{
|
||||||
|
Log_DebugPrintf("DPCR <- 0x%08X", value);
|
||||||
|
m_DPCR.bits = value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 0x74:
|
||||||
|
{
|
||||||
|
m_DCIR = (m_DCIR & ~DCIR_WRITE_MASK) | (value & DCIR_WRITE_MASK);
|
||||||
|
Log_DebugPrintf("DCIR <- 0x%08X", m_DCIR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Log_ErrorPrintf("Unhandled register write: %02X <- %08X", offset, value);
|
Log_ErrorPrintf("Unhandled register write: %02X <- %08X", offset, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DMA::SetRequest(Channel channel, bool request)
|
||||||
|
{
|
||||||
|
ChannelState& cs = m_state[static_cast<u32>(channel)];
|
||||||
|
cs.request = request;
|
||||||
|
|
||||||
|
if (CanRunChannel(channel))
|
||||||
|
RunDMA(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DMA::CanRunChannel(Channel channel) const
|
||||||
|
{
|
||||||
|
if (!m_DPCR.GetMasterEnable(channel))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const ChannelState& cs = m_state[static_cast<u32>(channel)];
|
||||||
|
if (cs.channel_control.start_trigger)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return (cs.channel_control.enable_busy && cs.request);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DMA::RunDMA(Channel channel)
|
||||||
|
{
|
||||||
|
ChannelState& cs = m_state[static_cast<u32>(channel)];
|
||||||
|
const PhysicalMemoryAddress memory_address = cs.base_address;
|
||||||
|
const bool copy_to_device = cs.channel_control.copy_to_device;
|
||||||
|
Log_DebugPrintf("Running DMA for channel %u", static_cast<u32>(channel));
|
||||||
|
Assert(Common::IsAlignedPow2(memory_address, 4));
|
||||||
|
|
||||||
|
// start/trigger bit is cleared on beginning of transfer
|
||||||
|
cs.channel_control.start_trigger = false;
|
||||||
|
|
||||||
|
switch (cs.channel_control.sync_mode)
|
||||||
|
{
|
||||||
|
case SyncMode::Manual:
|
||||||
|
{
|
||||||
|
const u32 word_count = cs.block_control.manual.GetWordCount();
|
||||||
|
Log_DebugPrintf(" ... copying %u words %s 0x%08X", word_count, copy_to_device ? "from" : "to", memory_address);
|
||||||
|
if (copy_to_device)
|
||||||
|
{
|
||||||
|
for (u32 i = 0; i < word_count; i++)
|
||||||
|
{
|
||||||
|
u32 memory_value = 0;
|
||||||
|
m_bus->DispatchAccess<MemoryAccessType::Read, MemoryAccessSize::Word>(memory_address, memory_address,
|
||||||
|
memory_value);
|
||||||
|
DMAWrite(channel, memory_value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (u32 i = 0; i < word_count; i++)
|
||||||
|
{
|
||||||
|
u32 memory_value = DMARead(channel);
|
||||||
|
m_bus->DispatchAccess<MemoryAccessType::Write, MemoryAccessSize::Word>(memory_address, memory_address,
|
||||||
|
memory_value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SyncMode::Request:
|
||||||
|
case SyncMode::LinkedList:
|
||||||
|
default:
|
||||||
|
Panic("Unimplemented sync mode");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// start/busy bit is cleared on end of transfer
|
||||||
|
cs.channel_control.enable_busy = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 DMA::DMARead(Channel channel)
|
||||||
|
{
|
||||||
|
switch (channel)
|
||||||
|
{
|
||||||
|
case Channel::OTC:
|
||||||
|
{
|
||||||
|
// we just return zeros here.. guessing it's pulled low?
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Channel::MDECin:
|
||||||
|
case Channel::MDECout:
|
||||||
|
case Channel::GPU:
|
||||||
|
case Channel::CDROM:
|
||||||
|
case Channel::SPU:
|
||||||
|
case Channel::PIO:
|
||||||
|
default:
|
||||||
|
Panic("Unhandled DMA channel write");
|
||||||
|
return UINT32_C(0xFFFFFFFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DMA::DMAWrite(Channel channel, u32 value)
|
||||||
|
{
|
||||||
|
Panic("Unhandled DMA channel write");
|
||||||
|
}
|
||||||
|
|
|
@ -34,18 +34,33 @@ public:
|
||||||
u32 ReadRegister(u32 offset);
|
u32 ReadRegister(u32 offset);
|
||||||
void WriteRegister(u32 offset, u32 value);
|
void WriteRegister(u32 offset, u32 value);
|
||||||
|
|
||||||
|
void SetRequest(Channel channel, bool request);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Bus* m_bus = nullptr;
|
static constexpr PhysicalMemoryAddress BASE_ADDRESS_MASK = UINT32_C(0x00FFFFFF);
|
||||||
GPU* m_gpu = nullptr;
|
|
||||||
|
|
||||||
enum class SyncMode : u32
|
enum class SyncMode : u32
|
||||||
{
|
{
|
||||||
Word = 0,
|
Manual = 0,
|
||||||
Block = 1,
|
Request = 1,
|
||||||
LinkedList = 2,
|
LinkedList = 2,
|
||||||
Reserved = 3
|
Reserved = 3
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// is everything enabled for a channel to operate?
|
||||||
|
bool CanRunChannel(Channel channel) const;
|
||||||
|
|
||||||
|
void RunDMA(Channel channel);
|
||||||
|
|
||||||
|
// from device -> memory
|
||||||
|
u32 DMARead(Channel channel);
|
||||||
|
|
||||||
|
// from memory -> device
|
||||||
|
void DMAWrite(Channel channel, u32 value);
|
||||||
|
|
||||||
|
Bus* m_bus = nullptr;
|
||||||
|
GPU* m_gpu = nullptr;
|
||||||
|
|
||||||
struct ChannelState
|
struct ChannelState
|
||||||
{
|
{
|
||||||
u32 base_address;
|
u32 base_address;
|
||||||
|
@ -56,25 +71,35 @@ private:
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
BitField<u32, u32, 0, 16> word_count;
|
BitField<u32, u32, 0, 16> word_count;
|
||||||
} word_mode;
|
|
||||||
|
u32 GetWordCount() const { return (word_count == 0) ? 0x10000 : word_count; }
|
||||||
|
} manual;
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
BitField<u32, u32, 0, 16> block_size;
|
BitField<u32, u32, 0, 16> block_size;
|
||||||
BitField<u32, u32, 16, 16> block_count;
|
BitField<u32, u32, 16, 16> block_count;
|
||||||
} block_mode;
|
|
||||||
|
u32 GetBlockSize() const { return (block_size == 0) ? 0x10000 : block_size; }
|
||||||
|
u32 GetBlockCount() const { return (block_count == 0) ? 0x10000 : block_count; }
|
||||||
|
} request;
|
||||||
} block_control;
|
} block_control;
|
||||||
|
|
||||||
union ChannelControl
|
union ChannelControl
|
||||||
{
|
{
|
||||||
u32 bits;
|
u32 bits;
|
||||||
BitField<u32, bool, 0, 1> direction_to_ram;
|
BitField<u32, bool, 0, 1> copy_to_device;
|
||||||
BitField<u32, bool, 1, 1> address_step_forward;
|
BitField<u32, bool, 1, 1> address_step_forward;
|
||||||
BitField<u32, bool, 8, 1> chopping_enable;
|
BitField<u32, bool, 8, 1> chopping_enable;
|
||||||
BitField<u32, SyncMode, 9, 2> sync_mode;
|
BitField<u32, SyncMode, 9, 2> sync_mode;
|
||||||
BitField<u32, u32, 16, 3> chopping_dma_window_size;
|
BitField<u32, u32, 16, 3> chopping_dma_window_size;
|
||||||
BitField<u32, u32, 20, 3> chopping_cpu_window_size;
|
BitField<u32, u32, 20, 3> chopping_cpu_window_size;
|
||||||
|
BitField<u32, bool, 24, 1> enable_busy;
|
||||||
BitField<u32, bool, 28, 1> start_trigger;
|
BitField<u32, bool, 28, 1> start_trigger;
|
||||||
|
|
||||||
|
static constexpr u32 WRITE_MASK = 0b01110001'01110111'00000111'00000011;
|
||||||
} channel_control;
|
} channel_control;
|
||||||
|
|
||||||
|
bool request = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::array<ChannelState, NUM_CHANNELS> m_state = {};
|
std::array<ChannelState, NUM_CHANNELS> m_state = {};
|
||||||
|
@ -83,8 +108,8 @@ private:
|
||||||
{
|
{
|
||||||
u32 bits;
|
u32 bits;
|
||||||
|
|
||||||
u8 GetPriority(Channel channel) { return ((bits >> (static_cast<u8>(channel) * 4)) & u32(3)); }
|
u8 GetPriority(Channel channel) const { return ((bits >> (static_cast<u8>(channel) * 4)) & u32(3)); }
|
||||||
bool GetMasterEnable(Channel channel)
|
bool GetMasterEnable(Channel channel) const
|
||||||
{
|
{
|
||||||
return ConvertToBoolUnchecked((bits >> (static_cast<u8>(channel) * 4 + 3)) & u32(1));
|
return ConvertToBoolUnchecked((bits >> (static_cast<u8>(channel) * 4 + 3)) & u32(1));
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
#include "gpu.h"
|
||||||
|
#include "YBaseLib/Log.h"
|
||||||
|
#include "bus.h"
|
||||||
|
Log_SetChannel(GPU);
|
||||||
|
|
||||||
|
GPU::GPU() = default;
|
||||||
|
|
||||||
|
GPU::~GPU() = default;
|
||||||
|
|
||||||
|
bool GPU::Initialize(Bus* bus, DMA* dma)
|
||||||
|
{
|
||||||
|
m_bus = bus;
|
||||||
|
m_dma = dma;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GPU::Reset()
|
||||||
|
{
|
||||||
|
SoftReset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GPU::SoftReset()
|
||||||
|
{
|
||||||
|
m_GPUSTAT.bits = 0x14802000;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 GPU::ReadRegister(u32 offset)
|
||||||
|
{
|
||||||
|
if (offset == 0x00)
|
||||||
|
{
|
||||||
|
// GPUREAD
|
||||||
|
Log_ErrorPrintf("GPUREAD");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if (offset == 0x04)
|
||||||
|
{
|
||||||
|
// GPUSTAT
|
||||||
|
return m_GPUSTAT.bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log_ErrorPrintf("Unhandled register read: %02X", offset);
|
||||||
|
return UINT32_C(0xFFFFFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GPU::WriteRegister(u32 offset, u32 value)
|
||||||
|
{
|
||||||
|
if (offset == 0x00)
|
||||||
|
WriteGP0(value);
|
||||||
|
else if (offset == 0x04)
|
||||||
|
WriteGP1(value);
|
||||||
|
else
|
||||||
|
Log_ErrorPrintf("Unhandled register write: %02X <- %08X", offset, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GPU::WriteGP0(u32 value)
|
||||||
|
{
|
||||||
|
const u8 command = Truncate8(value >> 24);
|
||||||
|
Log_ErrorPrintf("Unimplemented GP0 command 0x%02X", command);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GPU::WriteGP1(u32 value)
|
||||||
|
{
|
||||||
|
const u8 command = Truncate8(value >> 24);
|
||||||
|
Log_ErrorPrintf("Unimplemented GP1 command 0x%02X", command);
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
#pragma once
|
||||||
|
#include "common/bitfield.h"
|
||||||
|
#include "types.h"
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
class Bus;
|
||||||
|
class DMA;
|
||||||
|
|
||||||
|
class GPU
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GPU();
|
||||||
|
~GPU();
|
||||||
|
|
||||||
|
bool Initialize(Bus* bus, DMA* dma);
|
||||||
|
void Reset();
|
||||||
|
|
||||||
|
u32 ReadRegister(u32 offset);
|
||||||
|
void WriteRegister(u32 offset, u32 value);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void SoftReset();
|
||||||
|
void WriteGP0(u32 value);
|
||||||
|
void WriteGP1(u32 value);
|
||||||
|
|
||||||
|
Bus* m_bus = nullptr;
|
||||||
|
DMA* m_dma = nullptr;
|
||||||
|
|
||||||
|
union GPUSTAT
|
||||||
|
{
|
||||||
|
u32 bits;
|
||||||
|
BitField<u32, u8, 0, 4> texture_page_x_base;
|
||||||
|
BitField<u32, u8, 4, 1> texture_page_y_base;
|
||||||
|
BitField<u32, u8, 5, 2> semi_transparency;
|
||||||
|
BitField<u32, u8, 7, 2> texture_page_colors;
|
||||||
|
BitField<u32, bool, 9, 1> dither_enable;
|
||||||
|
BitField<u32, bool, 10, 1> draw_to_display_area;
|
||||||
|
BitField<u32, bool, 11, 1> draw_set_mask_bit;
|
||||||
|
BitField<u32, bool, 12, 1> draw_to_masked_pixels;
|
||||||
|
BitField<u32, bool, 13, 1> interlaced_field;
|
||||||
|
BitField<u32, bool, 14, 1> reverse_flag;
|
||||||
|
BitField<u32, bool, 15, 1> texture_disable;
|
||||||
|
BitField<u32, u8, 16, 1> horizontal_resolution_2;
|
||||||
|
BitField<u32, u8, 17, 2> horizontal_resolution_1;
|
||||||
|
BitField<u32, u8, 19, 1> vetical_resolution;
|
||||||
|
BitField<u32, bool, 20, 1> pal_mode;
|
||||||
|
BitField<u32, bool, 21, 1> display_area_color_depth_24;
|
||||||
|
BitField<u32, bool, 22, 1> vertical_interlace;
|
||||||
|
BitField<u32, bool, 23, 1> display_enable;
|
||||||
|
BitField<u32, bool, 24, 1> interrupt_request;
|
||||||
|
BitField<u32, bool, 25, 1> dma_data_request;
|
||||||
|
BitField<u32, bool, 26, 1> ready_to_recieve_cmd;
|
||||||
|
BitField<u32, bool, 27, 1> ready_to_send_vram;
|
||||||
|
BitField<u32, bool, 28, 1> ready_to_recieve_dma;
|
||||||
|
BitField<u32, u8, 29, 2> dma_direction;
|
||||||
|
BitField<u32, bool, 31, 1> drawing_even_line;
|
||||||
|
} m_GPUSTAT = {};
|
||||||
|
};
|
|
@ -39,6 +39,7 @@
|
||||||
<ClCompile Include="cpu_core.cpp" />
|
<ClCompile Include="cpu_core.cpp" />
|
||||||
<ClCompile Include="cpu_disasm.cpp" />
|
<ClCompile Include="cpu_disasm.cpp" />
|
||||||
<ClCompile Include="dma.cpp" />
|
<ClCompile Include="dma.cpp" />
|
||||||
|
<ClCompile Include="gpu.cpp" />
|
||||||
<ClCompile Include="system.cpp" />
|
<ClCompile Include="system.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -47,6 +48,7 @@
|
||||||
<ClInclude Include="cpu_disasm.h" />
|
<ClInclude Include="cpu_disasm.h" />
|
||||||
<ClInclude Include="cpu_types.h" />
|
<ClInclude Include="cpu_types.h" />
|
||||||
<ClInclude Include="dma.h" />
|
<ClInclude Include="dma.h" />
|
||||||
|
<ClInclude Include="gpu.h" />
|
||||||
<ClInclude Include="save_state_version.h" />
|
<ClInclude Include="save_state_version.h" />
|
||||||
<ClInclude Include="system.h" />
|
<ClInclude Include="system.h" />
|
||||||
<ClInclude Include="types.h" />
|
<ClInclude Include="types.h" />
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
<ClCompile Include="cpu_disasm.cpp" />
|
<ClCompile Include="cpu_disasm.cpp" />
|
||||||
<ClCompile Include="bus.cpp" />
|
<ClCompile Include="bus.cpp" />
|
||||||
<ClCompile Include="dma.cpp" />
|
<ClCompile Include="dma.cpp" />
|
||||||
|
<ClCompile Include="gpu.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="types.h" />
|
<ClInclude Include="types.h" />
|
||||||
|
@ -16,6 +17,7 @@
|
||||||
<ClInclude Include="cpu_disasm.h" />
|
<ClInclude Include="cpu_disasm.h" />
|
||||||
<ClInclude Include="bus.h" />
|
<ClInclude Include="bus.h" />
|
||||||
<ClInclude Include="dma.h" />
|
<ClInclude Include="dma.h" />
|
||||||
|
<ClInclude Include="gpu.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="cpu_core.inl" />
|
<None Include="cpu_core.inl" />
|
||||||
|
|
|
@ -9,10 +9,13 @@ bool System::Initialize()
|
||||||
if (!m_cpu.Initialize(&m_bus))
|
if (!m_cpu.Initialize(&m_bus))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!m_bus.Initialize(this, &m_dma, nullptr))
|
if (!m_bus.Initialize(this, &m_dma, &m_gpu))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!m_dma.Initialize(&m_bus, nullptr))
|
if (!m_dma.Initialize(&m_bus, &m_gpu))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!m_gpu.Initialize(&m_bus, &m_dma))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -22,6 +25,8 @@ void System::Reset()
|
||||||
{
|
{
|
||||||
m_cpu.Reset();
|
m_cpu.Reset();
|
||||||
m_bus.Reset();
|
m_bus.Reset();
|
||||||
|
m_dma.Reset();
|
||||||
|
m_gpu.Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::RunFrame()
|
void System::RunFrame()
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "bus.h"
|
#include "bus.h"
|
||||||
#include "dma.h"
|
#include "dma.h"
|
||||||
|
#include "gpu.h"
|
||||||
#include "cpu_core.h"
|
#include "cpu_core.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
|
@ -19,4 +20,5 @@ private:
|
||||||
CPU::Core m_cpu;
|
CPU::Core m_cpu;
|
||||||
Bus m_bus;
|
Bus m_bus;
|
||||||
DMA m_dma;
|
DMA m_dma;
|
||||||
|
GPU m_gpu;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue