mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-08-08 00:59:44 +00:00
Restructure device some
This commit is contained in:
parent
669cff6571
commit
6b21b41b2f
3 changed files with 102 additions and 66 deletions
|
@ -10,6 +10,7 @@
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
#include "Common/Assert.h"
|
#include "Common/Assert.h"
|
||||||
|
#include "Common/ChunkFile.h"
|
||||||
#include "Common/EnumFormatter.h"
|
#include "Common/EnumFormatter.h"
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
#include "Core/Debugger/Debugger_SymbolMap.h"
|
#include "Core/Debugger/Debugger_SymbolMap.h"
|
||||||
|
@ -25,47 +26,70 @@ std::string_view GetAVERegisterName(u8 address);
|
||||||
|
|
||||||
namespace Common
|
namespace Common
|
||||||
{
|
{
|
||||||
void I2CBusOld::AddSlave(I2CSlave* slave)
|
void I2CBusBase::AddSlave(I2CSlave* slave)
|
||||||
{
|
{
|
||||||
m_slaves.emplace_back(slave);
|
m_slaves.emplace_back(slave);
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2CBusOld::RemoveSlave(I2CSlave* slave)
|
void I2CBusBase::RemoveSlave(I2CSlave* slave)
|
||||||
{
|
{
|
||||||
m_slaves.erase(std::remove(m_slaves.begin(), m_slaves.end(), slave), m_slaves.end());
|
m_slaves.erase(std::remove(m_slaves.begin(), m_slaves.end(), slave), m_slaves.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2CBusOld::Reset()
|
void I2CBusBase::Reset()
|
||||||
{
|
{
|
||||||
m_slaves.clear();
|
m_slaves.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
int I2CBusOld::BusRead(u8 slave_addr, u8 addr, int count, u8* data_out)
|
I2CSlave* I2CBusBase::GetSlave(u8 slave_addr)
|
||||||
{
|
{
|
||||||
for (auto& slave : m_slaves)
|
for (I2CSlave* slave : m_slaves)
|
||||||
{
|
{
|
||||||
auto const bytes_read = slave->BusRead(slave_addr, addr, count, data_out);
|
if (slave->Matches(slave_addr))
|
||||||
|
return slave;
|
||||||
// A slave responded, we are done.
|
|
||||||
if (bytes_read)
|
|
||||||
return bytes_read;
|
|
||||||
}
|
}
|
||||||
|
return nullptr;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int I2CBusOld::BusWrite(u8 slave_addr, u8 addr, int count, const u8* data_in)
|
int I2CBusSimple::BusRead(u8 slave_addr, u8 addr, int count, u8* data_out)
|
||||||
{
|
{
|
||||||
for (auto& slave : m_slaves)
|
I2CSlave* slave = GetSlave(slave_addr);
|
||||||
|
if (slave != nullptr)
|
||||||
{
|
{
|
||||||
auto const bytes_written = slave->BusWrite(slave_addr, addr, count, data_in);
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
// A slave responded, we are done.
|
// TODO: Does this make sense? The transmitter can't NACK a read... it's the receiver that
|
||||||
if (bytes_written)
|
// does that
|
||||||
return bytes_written;
|
auto byte = slave->ReadByte(addr + i);
|
||||||
|
if (byte.has_value())
|
||||||
|
data_out[i] = byte.value();
|
||||||
|
else
|
||||||
|
return i;
|
||||||
}
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int I2CBusSimple::BusWrite(u8 slave_addr, u8 addr, int count, const u8* data_in)
|
||||||
|
{
|
||||||
|
I2CSlave* slave = GetSlave(slave_addr);
|
||||||
|
if (slave != nullptr)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
if (!slave->WriteByte(addr + i, data_in[i]))
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool I2CBus::GetSCL() const
|
bool I2CBus::GetSCL() const
|
||||||
|
@ -310,6 +334,17 @@ void I2CBus::SCLFallingEdge(const bool sda)
|
||||||
// Dolphin_Debugger::PrintCallstack(Common::Log::LogType::WII_IPC, Common::Log::LogLevel::LINFO);
|
// Dolphin_Debugger::PrintCallstack(Common::Log::LogType::WII_IPC, Common::Log::LogLevel::LINFO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void I2CBus::DoState(PointerWrap& p)
|
||||||
|
{
|
||||||
|
p.Do(state);
|
||||||
|
p.Do(bit_counter);
|
||||||
|
p.Do(current_byte);
|
||||||
|
p.Do(i2c_address);
|
||||||
|
p.Do(device_address);
|
||||||
|
// TODO: verify m_devices is the same so that the state is compatible.
|
||||||
|
// (We don't take ownership of saving/loading m_devices, though).
|
||||||
|
}
|
||||||
|
|
||||||
}; // namespace Common
|
}; // namespace Common
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
|
|
|
@ -9,70 +9,67 @@
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
|
||||||
|
class PointerWrap;
|
||||||
|
|
||||||
namespace Common
|
namespace Common
|
||||||
{
|
{
|
||||||
class I2CBusOld;
|
|
||||||
|
|
||||||
class I2CSlave
|
class I2CSlave
|
||||||
{
|
{
|
||||||
friend I2CBusOld;
|
public:
|
||||||
|
virtual bool Matches(u8 slave_addr) = 0;
|
||||||
protected:
|
virtual std::optional<u8> ReadByte(u8 addr) = 0;
|
||||||
virtual ~I2CSlave() = default;
|
virtual bool WriteByte(u8 addr, u8 value) = 0;
|
||||||
|
|
||||||
virtual int BusRead(u8 slave_addr, u8 addr, int count, u8* data_out) = 0;
|
|
||||||
virtual int BusWrite(u8 slave_addr, u8 addr, int count, const u8* data_in) = 0;
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
static int RawRead(T* reg_data, u8 addr, int count, u8* data_out)
|
|
||||||
{
|
|
||||||
static_assert(std::is_standard_layout_v<T> && std::is_trivially_copyable_v<T>);
|
|
||||||
static_assert(0x100 == sizeof(T));
|
|
||||||
|
|
||||||
// TODO: addr wraps around after 0xff
|
|
||||||
|
|
||||||
u8* src = reinterpret_cast<u8*>(reg_data) + addr;
|
|
||||||
count = std::min(count, int(reinterpret_cast<u8*>(reg_data + 1) - src));
|
|
||||||
|
|
||||||
std::copy_n(src, count, data_out);
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
static int RawWrite(T* reg_data, u8 addr, int count, const u8* data_in)
|
|
||||||
{
|
|
||||||
static_assert(std::is_standard_layout_v<T> && std::is_trivially_copyable_v<T>);
|
|
||||||
static_assert(0x100 == sizeof(T));
|
|
||||||
|
|
||||||
// TODO: addr wraps around after 0xff
|
|
||||||
|
|
||||||
u8* dst = reinterpret_cast<u8*>(reg_data) + addr;
|
|
||||||
count = std::min(count, int(reinterpret_cast<u8*>(reg_data + 1) - dst));
|
|
||||||
|
|
||||||
std::copy_n(data_in, count, dst);
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class I2CBusOld
|
template <u8 slave_addr_val, typename T>
|
||||||
|
class I2CSlaveSimple : I2CSlave
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
bool Matches(u8 slave_addr) override { return slave_addr == slave_addr_val; }
|
||||||
|
std::optional<u8> ReadByte(u8 addr) { return data_bytes[addr]; }
|
||||||
|
bool WriteByte(u8 addr, u8 value)
|
||||||
|
{
|
||||||
|
data_bytes[addr] = value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
T data;
|
||||||
|
std::array<u8, 0x100> data_bytes;
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(std::is_standard_layout_v<T> && std::is_trivially_copyable_v<T>);
|
||||||
|
static_assert(sizeof(T) == 0x100);
|
||||||
|
};
|
||||||
|
|
||||||
|
class I2CBusBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~I2CBusBase() = default;
|
||||||
|
|
||||||
void AddSlave(I2CSlave* slave);
|
void AddSlave(I2CSlave* slave);
|
||||||
void RemoveSlave(I2CSlave* slave);
|
void RemoveSlave(I2CSlave* slave);
|
||||||
|
|
||||||
void Reset();
|
void Reset();
|
||||||
|
|
||||||
// TODO: change int to u16 or something
|
protected:
|
||||||
int BusRead(u8 slave_addr, u8 addr, int count, u8* data_out);
|
// Returns nullptr if there is no match
|
||||||
int BusWrite(u8 slave_addr, u8 addr, int count, const u8* data_in);
|
I2CSlave* GetSlave(u8 slave_addr);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Pointers are unowned:
|
// Pointers are unowned:
|
||||||
std::vector<I2CSlave*> m_slaves;
|
std::vector<I2CSlave*> m_slaves;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class I2CBusSimple : public I2CBusBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// TODO: change int to u16 or something
|
||||||
|
int BusRead(u8 slave_addr, u8 addr, int count, u8* data_out);
|
||||||
|
int BusWrite(u8 slave_addr, u8 addr, int count, const u8* data_in);
|
||||||
|
};
|
||||||
|
|
||||||
// An I²C bus implementation accessed via bit-banging.
|
// An I²C bus implementation accessed via bit-banging.
|
||||||
// A few assumptions and limitations exist:
|
// A few assumptions and limitations exist:
|
||||||
// - All devices support both writes and reads.
|
// - All devices support both writes and reads.
|
||||||
|
@ -91,7 +88,7 @@ private:
|
||||||
// read from a different device would result in reading from the last used device address (without
|
// read from a different device would result in reading from the last used device address (without
|
||||||
// any warning).
|
// any warning).
|
||||||
// - 10-bit addressing and other reserved addressing modes are not implemented.
|
// - 10-bit addressing and other reserved addressing modes are not implemented.
|
||||||
class I2CBus
|
class I2CBus : public I2CBusBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum class State
|
enum class State
|
||||||
|
@ -114,6 +111,8 @@ public:
|
||||||
bool GetSCL() const;
|
bool GetSCL() const;
|
||||||
bool GetSDA() const;
|
bool GetSDA() const;
|
||||||
|
|
||||||
|
void DoState(PointerWrap& p);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Start();
|
void Start();
|
||||||
void Stop();
|
void Stop();
|
||||||
|
|
|
@ -144,6 +144,8 @@ void WiiIPC::DoState(PointerWrap& p)
|
||||||
p.Do(m_arm_irq_masks);
|
p.Do(m_arm_irq_masks);
|
||||||
p.Do(m_gpio_dir);
|
p.Do(m_gpio_dir);
|
||||||
p.Do(m_gpio_out);
|
p.Do(m_gpio_out);
|
||||||
|
i2c_state.DoState(p);
|
||||||
|
p.Do(ave_state);
|
||||||
p.Do(m_resets);
|
p.Do(m_resets);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue