Bus: Handle unaligned byte writes to SPU

This commit is contained in:
Connor McLaughlin 2020-05-20 18:56:41 +10:00
parent c8a00c58eb
commit a693437bc9

View file

@ -19,7 +19,10 @@
Log_SetChannel(Bus); Log_SetChannel(Bus);
#define FIXUP_WORD_READ_OFFSET(offset) ((offset) & ~u32(3)) #define FIXUP_WORD_READ_OFFSET(offset) ((offset) & ~u32(3))
#define FIXUP_WORD_READ_VALUE(offset, value) ((value) >> (((offset)&u32(3)) * 8)) #define FIXUP_WORD_READ_VALUE(offset, value) ((value) >> (((offset)&u32(3)) * 8u))
#define FIXUP_HALFWORD_READ_OFFSET(offset) ((offset) & ~u32(1))
#define FIXUP_HALFWORD_READ_VALUE(offset, value) ((value) >> (((offset)&u32(1)) * 8u))
#define FIXUP_HALFWORD_WRITE_VALUE(offset, value) ((value) << (((offset)&u32(1)) * 8u))
// Offset and value remapping for (w32) registers from nocash docs. // Offset and value remapping for (w32) registers from nocash docs.
void FixupUnalignedWordAccessW32(u32& offset, u32& value) void FixupUnalignedWordAccessW32(u32& offset, u32& value)
@ -487,16 +490,27 @@ void Bus::DoWriteTimers(MemoryAccessSize size, u32 offset, u32 value)
u32 Bus::DoReadSPU(MemoryAccessSize size, u32 offset) u32 Bus::DoReadSPU(MemoryAccessSize size, u32 offset)
{ {
// 32-bit reads are read as two 16-bit accesses. switch (size)
if (size == MemoryAccessSize::Word)
{ {
const u16 lsb = m_spu->ReadRegister(offset); case MemoryAccessSize::Word:
const u16 msb = m_spu->ReadRegister(offset + 2); {
return ZeroExtend32(lsb) | (ZeroExtend32(msb) << 16); // 32-bit reads are read as two 16-bit accesses.
} const u16 lsb = m_spu->ReadRegister(offset);
else const u16 msb = m_spu->ReadRegister(offset + 2);
{ return ZeroExtend32(lsb) | (ZeroExtend32(msb) << 16);
return ZeroExtend32(m_spu->ReadRegister(offset)); }
case MemoryAccessSize::HalfWord:
{
return ZeroExtend32(m_spu->ReadRegister(offset));
}
case MemoryAccessSize::Byte:
default:
{
u16 value = m_spu->ReadRegister(FIXUP_HALFWORD_READ_OFFSET(offset));
return FIXUP_HALFWORD_READ_VALUE(offset, value);
}
} }
} }
@ -504,16 +518,29 @@ void Bus::DoWriteSPU(MemoryAccessSize size, u32 offset, u32 value)
{ {
// 32-bit writes are written as two 16-bit writes. // 32-bit writes are written as two 16-bit writes.
// TODO: Ignore if address is not aligned. // TODO: Ignore if address is not aligned.
if (size == MemoryAccessSize::Word) switch (size)
{ {
Assert(Common::IsAlignedPow2(offset, 2)); case MemoryAccessSize::Word:
m_spu->WriteRegister(offset, Truncate16(value)); {
m_spu->WriteRegister(offset + 2, Truncate16(value >> 16)); DebugAssert(Common::IsAlignedPow2(offset, 2));
return; m_spu->WriteRegister(offset, Truncate16(value));
} m_spu->WriteRegister(offset + 2, Truncate16(value >> 16));
return;
}
Assert(Common::IsAlignedPow2(offset, 2)); case MemoryAccessSize::HalfWord:
m_spu->WriteRegister(offset, Truncate16(value)); {
DebugAssert(Common::IsAlignedPow2(offset, 2));
m_spu->WriteRegister(offset, Truncate16(value));
return;
}
case MemoryAccessSize::Byte:
{
m_spu->WriteRegister(FIXUP_HALFWORD_READ_OFFSET(offset), Truncate16(FIXUP_HALFWORD_READ_VALUE(offset, value)));
return;
}
}
} }
void Bus::DoInvalidateCodeCache(u32 page_index) void Bus::DoInvalidateCodeCache(u32 page_index)