Restructure device some

This commit is contained in:
Pokechu22 2022-09-03 17:41:22 -07:00
parent 669cff6571
commit 6b21b41b2f
3 changed files with 102 additions and 66 deletions

View file

@ -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 <>

View file

@ -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();

View file

@ -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);
}