mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-04-20 19:44:57 +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 "Common/Assert.h"
|
||||
#include "Common/ChunkFile.h"
|
||||
#include "Common/EnumFormatter.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "Core/Debugger/Debugger_SymbolMap.h"
|
||||
|
@ -25,47 +26,70 @@ std::string_view GetAVERegisterName(u8 address);
|
|||
|
||||
namespace Common
|
||||
{
|
||||
void I2CBusOld::AddSlave(I2CSlave* slave)
|
||||
void I2CBusBase::AddSlave(I2CSlave* 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());
|
||||
}
|
||||
|
||||
void I2CBusOld::Reset()
|
||||
void I2CBusBase::Reset()
|
||||
{
|
||||
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);
|
||||
|
||||
// A slave responded, we are done.
|
||||
if (bytes_read)
|
||||
return bytes_read;
|
||||
if (slave->Matches(slave_addr))
|
||||
return slave;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// A slave responded, we are done.
|
||||
if (bytes_written)
|
||||
return bytes_written;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
// TODO: Does this make sense? The transmitter can't NACK a read... it's the receiver that
|
||||
// does that
|
||||
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
|
||||
|
@ -310,6 +334,17 @@ void I2CBus::SCLFallingEdge(const bool sda)
|
|||
// 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
|
||||
|
||||
template <>
|
||||
|
|
|
@ -9,70 +9,67 @@
|
|||
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
class PointerWrap;
|
||||
|
||||
namespace Common
|
||||
{
|
||||
class I2CBusOld;
|
||||
|
||||
class I2CSlave
|
||||
{
|
||||
friend I2CBusOld;
|
||||
|
||||
protected:
|
||||
virtual ~I2CSlave() = default;
|
||||
|
||||
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;
|
||||
}
|
||||
public:
|
||||
virtual bool Matches(u8 slave_addr) = 0;
|
||||
virtual std::optional<u8> ReadByte(u8 addr) = 0;
|
||||
virtual bool WriteByte(u8 addr, u8 value) = 0;
|
||||
};
|
||||
|
||||
class I2CBusOld
|
||||
template <u8 slave_addr_val, typename T>
|
||||
class I2CSlaveSimple : I2CSlave
|
||||
{
|
||||
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 RemoveSlave(I2CSlave* slave);
|
||||
|
||||
void Reset();
|
||||
|
||||
// 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);
|
||||
protected:
|
||||
// Returns nullptr if there is no match
|
||||
I2CSlave* GetSlave(u8 slave_addr);
|
||||
|
||||
private:
|
||||
// Pointers are unowned:
|
||||
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.
|
||||
// A few assumptions and limitations exist:
|
||||
// - 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
|
||||
// any warning).
|
||||
// - 10-bit addressing and other reserved addressing modes are not implemented.
|
||||
class I2CBus
|
||||
class I2CBus : public I2CBusBase
|
||||
{
|
||||
public:
|
||||
enum class State
|
||||
|
@ -114,6 +111,8 @@ public:
|
|||
bool GetSCL() const;
|
||||
bool GetSDA() const;
|
||||
|
||||
void DoState(PointerWrap& p);
|
||||
|
||||
private:
|
||||
void Start();
|
||||
void Stop();
|
||||
|
|
|
@ -144,6 +144,8 @@ void WiiIPC::DoState(PointerWrap& p)
|
|||
p.Do(m_arm_irq_masks);
|
||||
p.Do(m_gpio_dir);
|
||||
p.Do(m_gpio_out);
|
||||
i2c_state.DoState(p);
|
||||
p.Do(ave_state);
|
||||
p.Do(m_resets);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue