Skip to content

Commit

Permalink
SI: Add 16bit accessors for SI IO buffer
Browse files Browse the repository at this point in the history
Dolphin has traditionally treated the SI IO buffer (128 bytes) as a set of
32 little endian u32s. This works out fine if you only ever read/write
using aligned 32bit accesses. Different sized accesses or misaligned reads
will mess it up. Byte swapping reads/writes will fix this up, but all the
SI devices that use the SI IO buffer need to be fixed [TODO].
  • Loading branch information
booto committed Aug 15, 2018
1 parent 60f12e1 commit 74e919b
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 14 deletions.
57 changes: 56 additions & 1 deletion Source/Core/Core/HW/MMIO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "Common/Assert.h"
#include "Common/CommonTypes.h"
#include "Common/Swap.h"
#include "Core/HW/MMIOHandlers.h"

namespace MMIO
Expand Down Expand Up @@ -116,6 +117,50 @@ WriteHandlingMethod<T>* DirectWrite(volatile T* addr, u32 mask)
return new DirectHandlingMethod<T>((T*)addr, mask);
}

// DirectSwap: handling method holds a pointer to the value where to read/write the
// data from, as well as a mask that is used to restrict reading/writing only
// to a given set of bits. Bytes will be swapped on read/write.
template <typename T>
class DirectSwapHandlingMethod : public ReadHandlingMethod<T>, public WriteHandlingMethod<T>
{
public:
DirectSwapHandlingMethod(T* addr, u32 mask) : addr_(addr), mask_(mask) {}
virtual ~DirectSwapHandlingMethod() = default;
void AcceptReadVisitor(ReadHandlingMethodVisitor<T>& v) const override
{
v.VisitDirectSwap(addr_, mask_);
}

void AcceptWriteVisitor(WriteHandlingMethodVisitor<T>& v) const override
{
v.VisitDirectSwap(addr_, mask_);
}

private:
T* addr_;
u32 mask_;
};
template <typename T>
ReadHandlingMethod<T>* DirectSwapRead(const T* addr, u32 mask)
{
return new DirectSwapHandlingMethod<T>(const_cast<T*>(addr), mask);
}
template <typename T>
ReadHandlingMethod<T>* DirectSwapRead(volatile const T* addr, u32 mask)
{
return new DirectSwapHandlingMethod<T>((T*)addr, mask);
}
template <typename T>
WriteHandlingMethod<T>* DirectSwapWrite(T* addr, u32 mask)
{
return new DirectSwapHandlingMethod<T>(addr, mask);
}
template <typename T>
WriteHandlingMethod<T>* DirectSwapWrite(volatile T* addr, u32 mask)
{
return new DirectSwapHandlingMethod<T>((T*)addr, mask);
}

// Complex: holds a lambda that is called when a read or a write is executed.
// This gives complete control to the user as to what is going to happen during
// that read or write, but reduces the optimization potential.
Expand Down Expand Up @@ -321,6 +366,11 @@ void ReadHandler<T>::ResetMethod(ReadHandlingMethod<T>* method)
ret = [addr, mask](u32) { return *addr & mask; };
}

void VisitDirectSwap(const T* addr, u32 mask) override
{
ret = [addr, mask](u32) { return Common::FromBigEndian(*addr & mask); };
}

void VisitComplex(const std::function<T(u32)>* lambda) override { ret = *lambda; }
};

Expand Down Expand Up @@ -375,6 +425,11 @@ void WriteHandler<T>::ResetMethod(WriteHandlingMethod<T>* method)
ret = [ptr, mask](u32, T val) { *ptr = val & mask; };
}

void VisitDirectSwap(T* ptr, u32 mask) override
{
ret = [ptr, mask](u32, T val) { *ptr = Common::FromBigEndian(val & mask); };
}

void VisitComplex(const std::function<void(u32, T)>* lambda) override { ret = *lambda; }
};

Expand All @@ -387,4 +442,4 @@ void WriteHandler<T>::ResetMethod(WriteHandlingMethod<T>* method)
#define MaybeExtern
MMIO_PUBLIC_SPECIALIZATIONS()
#undef MaybeExtern
}
} // namespace MMIO
20 changes: 19 additions & 1 deletion Source/Core/Core/HW/MMIOHandlers.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,18 @@ WriteHandlingMethod<T>* DirectWrite(T* addr, u32 mask = 0xFFFFFFFF);
template <typename T>
WriteHandlingMethod<T>* DirectWrite(volatile T* addr, u32 mask = 0xFFFFFFFF);

// DirectSwap: use when all the MMIO does is read/write the given value to/from a
// global variable, with an optional mask applied on the read/written value. The
// bytes of the value will be swapped before read/write.
template <typename T>
ReadHandlingMethod<T>* DirectSwapRead(const T* addr, u32 mask = 0xFFFFFFFF);
template <typename T>
ReadHandlingMethod<T>* DirectSwapRead(volatile const T* addr, u32 mask = 0xFFFFFFFF);
template <typename T>
WriteHandlingMethod<T>* DirectSwapWrite(T* addr, u32 mask = 0xFFFFFFFF);
template <typename T>
WriteHandlingMethod<T>* DirectSwapWrite(volatile T* addr, u32 mask = 0xFFFFFFFF);

// Complex: use when no other handling method fits your needs. These allow you
// to directly provide a function that will be called when a read/write needs
// to be done.
Expand Down Expand Up @@ -102,6 +114,7 @@ class ReadHandlingMethodVisitor
public:
virtual void VisitConstant(T value) = 0;
virtual void VisitDirect(const T* addr, u32 mask) = 0;
virtual void VisitDirectSwap(const T* addr, u32 mask) = 0;
virtual void VisitComplex(const std::function<T(u32)>* lambda) = 0;
};
template <typename T>
Expand All @@ -110,6 +123,7 @@ class WriteHandlingMethodVisitor
public:
virtual void VisitNop() = 0;
virtual void VisitDirect(T* addr, u32 mask) = 0;
virtual void VisitDirectSwap(T* addr, u32 mask) = 0;
virtual void VisitComplex(const std::function<void(u32, T)>* lambda) = 0;
};

Expand Down Expand Up @@ -207,6 +221,10 @@ class WriteHandler
MaybeExtern template ReadHandlingMethod<T>* DirectRead(volatile const T* addr, u32 mask); \
MaybeExtern template WriteHandlingMethod<T>* DirectWrite(T* addr, u32 mask); \
MaybeExtern template WriteHandlingMethod<T>* DirectWrite(volatile T* addr, u32 mask); \
MaybeExtern template ReadHandlingMethod<T>* DirectSwapRead(const T* addr, u32 mask); \
MaybeExtern template ReadHandlingMethod<T>* DirectSwapRead(volatile const T* addr, u32 mask); \
MaybeExtern template WriteHandlingMethod<T>* DirectSwapWrite(T* addr, u32 mask); \
MaybeExtern template WriteHandlingMethod<T>* DirectSwapWrite(volatile T* addr, u32 mask); \
MaybeExtern template ReadHandlingMethod<T>* ComplexRead<T>(std::function<T(u32)>); \
MaybeExtern template WriteHandlingMethod<T>* ComplexWrite<T>(std::function<void(u32, T)>); \
MaybeExtern template ReadHandlingMethod<T>* InvalidRead<T>(); \
Expand Down Expand Up @@ -237,4 +255,4 @@ class WriteHandler
#define MaybeExtern extern
MMIO_PUBLIC_SPECIALIZATIONS()
#undef MaybeExtern
}
} // namespace MMIO
14 changes: 11 additions & 3 deletions Source/Core/Core/HW/SI/SI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ enum
SI_COM_CSR = 0x34,
SI_STATUS_REG = 0x38,
SI_EXI_CLOCK_COUNT = 0x3C,
SI_IO_BUFFER = 0x80,
};

// SI Channel Output
Expand Down Expand Up @@ -416,10 +417,17 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
// Register SI buffer direct accesses.
for (size_t i = 0; i < s_si_buffer.size(); i += sizeof(u32))
{
const u32 address = base | static_cast<u32>(s_si_buffer.size() + i);
const u32 address = base | static_cast<u32>(SI_IO_BUFFER + i);

mmio->Register(address, MMIO::DirectRead<u32>((u32*)&s_si_buffer[i]),
MMIO::DirectWrite<u32>((u32*)&s_si_buffer[i]));
mmio->Register(address, MMIO::DirectSwapRead<u32>((u32*)&s_si_buffer[i]),
MMIO::DirectSwapWrite<u32>((u32*)&s_si_buffer[i]));
}
for (size_t i = 0; i < s_si_buffer.size(); i += sizeof(u16))
{
const u32 address = base | static_cast<u32>(SI_IO_BUFFER + i);

mmio->Register(address, MMIO::DirectSwapRead<u16>((u16*)&s_si_buffer[i]),
MMIO::DirectSwapWrite<u16>((u16*)&s_si_buffer[i]));
}

// In and out for the 4 SI channels.
Expand Down
15 changes: 8 additions & 7 deletions Source/Core/Core/HW/SI/SI_DeviceGCController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "Common/CommonTypes.h"
#include "Common/Logging/Log.h"
#include "Common/MsgHandler.h"
#include "Common/Swap.h"
#include "Core/CoreTiming.h"
#include "Core/HW/GCPad.h"
#include "Core/HW/ProcessorInterface.h"
Expand Down Expand Up @@ -50,21 +51,21 @@ int CSIDevice_GCController::RunBuffer(u8* buffer, int length)
GCPadStatus pad_status = GetPadStatus();
if (!pad_status.isConnected)
{
constexpr u32 reply = SI_ERROR_NO_RESPONSE;
u32 reply = Common::swap32(SI_ERROR_NO_RESPONSE);
std::memcpy(buffer, &reply, sizeof(reply));
return 4;
}

// Read the command
EBufferCommands command = static_cast<EBufferCommands>(buffer[3]);
EBufferCommands command = static_cast<EBufferCommands>(buffer[0]);

// Handle it
switch (command)
{
case CMD_RESET:
case CMD_ID:
{
constexpr u32 id = SI_GC_CONTROLLER;
u32 id = Common::swap32(SI_GC_CONTROLLER);
std::memcpy(buffer, &id, sizeof(id));
break;
}
Expand All @@ -76,8 +77,8 @@ int CSIDevice_GCController::RunBuffer(u8* buffer, int length)
GetData(high, low);
for (int i = 0; i < (length - 1) / 2; i++)
{
buffer[i + 0] = (high >> (i * 8)) & 0xff;
buffer[i + 4] = (low >> (i * 8)) & 0xff;
buffer[i + 0] = (high >> (24 - (i * 8))) & 0xff;
buffer[i + 4] = (low >> (24 - (i * 8))) & 0xff;
}
}
break;
Expand All @@ -92,7 +93,7 @@ int CSIDevice_GCController::RunBuffer(u8* buffer, int length)
u8* calibration = reinterpret_cast<u8*>(&m_origin);
for (int i = 0; i < (int)sizeof(SOrigin); i++)
{
buffer[i ^ 3] = *calibration++;
buffer[i] = *calibration++;
}
}
break;
Expand All @@ -108,7 +109,7 @@ int CSIDevice_GCController::RunBuffer(u8* buffer, int length)
u8* calibration = reinterpret_cast<u8*>(&m_origin);
for (int i = 0; i < (int)sizeof(SOrigin); i++)
{
buffer[i ^ 3] = *calibration++;
buffer[i] = *calibration++;
}
}
break;
Expand Down
21 changes: 19 additions & 2 deletions Source/Core/Core/PowerPC/Jit64Common/EmuCodeBlock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,11 @@ class MMIOReadCodeGenerator : public MMIO::ReadHandlingMethodVisitor<T>
void VisitConstant(T value) override { LoadConstantToReg(8 * sizeof(T), value); }
void VisitDirect(const T* addr, u32 mask) override
{
LoadAddrMaskToReg(8 * sizeof(T), addr, mask);
LoadAddrMaskToReg(8 * sizeof(T), addr, mask, false);
}
void VisitDirectSwap(const T* addr, u32 mask) override
{
LoadAddrMaskToReg(8 * sizeof(T), addr, mask, true);
}
void VisitComplex(const std::function<T(u32)>* lambda) override
{
Expand Down Expand Up @@ -251,7 +255,7 @@ class MMIOReadCodeGenerator : public MMIO::ReadHandlingMethodVisitor<T>
m_code->MOVZX(32, sbits, m_dst_reg, arg);
}

void LoadAddrMaskToReg(int sbits, const void* ptr, u32 mask)
void LoadAddrMaskToReg(int sbits, const void* ptr, u32 mask, bool swap)
{
m_code->MOV(64, R(RSCRATCH), ImmPtr(ptr));
// If we do not need to mask, we can do the sign extend while loading
Expand All @@ -269,6 +273,19 @@ class MMIOReadCodeGenerator : public MMIO::ReadHandlingMethodVisitor<T>
if (m_sign_extend)
m_code->MOVSX(32, sbits, m_dst_reg, R(m_dst_reg));
}
if (swap && (sbits != 8))
{
m_code->BSWAP(64, m_dst_reg);
switch (sbits)
{
case 16:
m_code->SHR(64, R(m_dst_reg), Imm8(48));
break;
case 32:
m_code->SHR(64, R(m_dst_reg), Imm8(32));
break;
}
}
}

void CallLambda(int sbits, const std::function<T(u32)>* lambda)
Expand Down

0 comments on commit 74e919b

Please sign in to comment.