Skip to content

Commit

Permalink
Merge pull request #11639 from AdmiralCurtiss/exi-class
Browse files Browse the repository at this point in the history
HW: Refactor ExpansionInterface and MemoryInterface to classes.
  • Loading branch information
lioncash authored Mar 11, 2023
2 parents e4df388 + 84542d9 commit 7b5c989
Show file tree
Hide file tree
Showing 15 changed files with 269 additions and 287 deletions.
2 changes: 1 addition & 1 deletion Source/Core/Core/Core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -783,7 +783,7 @@ static bool PauseAndLock(Core::System& system, bool do_lock, bool unpause_on_unl
was_unpaused = system.GetCPU().PauseAndLock(true);
}

ExpansionInterface::PauseAndLock(do_lock, false);
system.GetExpansionInterface().PauseAndLock(do_lock, false);

// audio has to come after CPU, because CPU thread can wait for audio thread (m_throttle).
system.GetDSP().GetDSPEmulator()->PauseAndLock(do_lock, false);
Expand Down
134 changes: 52 additions & 82 deletions Source/Core/Core/HW/EXI/EXI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,28 +27,13 @@

namespace ExpansionInterface
{
struct ExpansionInterfaceState::Data
{
CoreTiming::EventType* event_type_change_device = nullptr;
CoreTiming::EventType* event_type_update_interrupts = nullptr;

std::array<std::unique_ptr<CEXIChannel>, MAX_EXI_CHANNELS> channels{};

bool using_overridden_sram = false;
};

ExpansionInterfaceState::ExpansionInterfaceState() : m_data(std::make_unique<Data>())
ExpansionInterfaceManager::ExpansionInterfaceManager(Core::System& system) : m_system(system)
{
}

ExpansionInterfaceState::~ExpansionInterfaceState() = default;
ExpansionInterfaceManager::~ExpansionInterfaceManager() = default;

static void ChangeDeviceCallback(Core::System& system, u64 userdata, s64 cyclesLate);
static void UpdateInterruptsCallback(Core::System& system, u64 userdata, s64 cycles_late);

namespace
{
void AddMemoryCard(Slot slot)
void ExpansionInterfaceManager::AddMemoryCard(Slot slot)
{
EXIDeviceType memorycard_device;
if (Movie::IsPlayingInput() && Movie::IsConfigSaved())
Expand Down Expand Up @@ -76,10 +61,8 @@ void AddMemoryCard(Slot slot)
memorycard_device = Config::Get(Config::GetInfoForEXIDevice(slot));
}

auto& state = Core::System::GetInstance().GetExpansionInterfaceState().GetData();
state.channels[SlotToEXIChannel(slot)]->AddDevice(memorycard_device, SlotToEXIDevice(slot));
m_channels[SlotToEXIChannel(slot)]->AddDevice(memorycard_device, SlotToEXIDevice(slot));
}
} // namespace

u8 SlotToEXIChannel(Slot slot)
{
Expand Down Expand Up @@ -113,20 +96,18 @@ u8 SlotToEXIDevice(Slot slot)
}
}

void Init(const Sram* override_sram)
void ExpansionInterfaceManager::Init(const Sram* override_sram)
{
auto& system = Core::System::GetInstance();
auto& state = system.GetExpansionInterfaceState().GetData();
auto& sram = system.GetSRAM();
auto& sram = m_system.GetSRAM();
if (override_sram)
{
sram = *override_sram;
state.using_overridden_sram = true;
m_using_overridden_sram = true;
}
else
{
InitSRAM(&sram, SConfig::GetInstance().m_strSRAM);
state.using_overridden_sram = false;
m_using_overridden_sram = false;
}

CEXIMemoryCard::Init();
Expand All @@ -149,141 +130,130 @@ void Init(const Sram* override_sram)
Memcard::HeaderData header_data;
Memcard::InitializeHeaderData(&header_data, flash_id, size_mbits, shift_jis, rtc_bias,
sram_language, format_time + i);
state.channels[i] = std::make_unique<CEXIChannel>(system, i, header_data);
m_channels[i] = std::make_unique<CEXIChannel>(m_system, i, header_data);
}
}

for (Slot slot : MEMCARD_SLOTS)
AddMemoryCard(slot);

state.channels[0]->AddDevice(EXIDeviceType::MaskROM, 1);
state.channels[SlotToEXIChannel(Slot::SP1)]->AddDevice(Config::Get(Config::MAIN_SERIAL_PORT_1),
SlotToEXIDevice(Slot::SP1));
state.channels[2]->AddDevice(EXIDeviceType::AD16, 0);
m_channels[0]->AddDevice(EXIDeviceType::MaskROM, 1);
m_channels[SlotToEXIChannel(Slot::SP1)]->AddDevice(Config::Get(Config::MAIN_SERIAL_PORT_1),
SlotToEXIDevice(Slot::SP1));
m_channels[2]->AddDevice(EXIDeviceType::AD16, 0);

auto& core_timing = system.GetCoreTiming();
state.event_type_change_device =
core_timing.RegisterEvent("ChangeEXIDevice", ChangeDeviceCallback);
state.event_type_update_interrupts =
auto& core_timing = m_system.GetCoreTiming();
m_event_type_change_device = core_timing.RegisterEvent("ChangeEXIDevice", ChangeDeviceCallback);
m_event_type_update_interrupts =
core_timing.RegisterEvent("EXIUpdateInterrupts", UpdateInterruptsCallback);
}

void Shutdown()
void ExpansionInterfaceManager::Shutdown()
{
auto& system = Core::System::GetInstance();
auto& state = system.GetExpansionInterfaceState().GetData();

for (auto& channel : state.channels)
for (auto& channel : m_channels)
channel.reset();

CEXIMemoryCard::Shutdown();

if (!state.using_overridden_sram)
if (!m_using_overridden_sram)
{
File::IOFile file(SConfig::GetInstance().m_strSRAM, "wb");
auto& sram = system.GetSRAM();
auto& sram = m_system.GetSRAM();
file.WriteArray(&sram, 1);
}
}

void DoState(PointerWrap& p)
void ExpansionInterfaceManager::DoState(PointerWrap& p)
{
auto& state = Core::System::GetInstance().GetExpansionInterfaceState().GetData();
for (auto& channel : state.channels)
for (auto& channel : m_channels)
channel->DoState(p);
}

void PauseAndLock(bool doLock, bool unpauseOnUnlock)
void ExpansionInterfaceManager::PauseAndLock(bool doLock, bool unpauseOnUnlock)
{
auto& state = Core::System::GetInstance().GetExpansionInterfaceState().GetData();
for (auto& channel : state.channels)
for (auto& channel : m_channels)
channel->PauseAndLock(doLock, unpauseOnUnlock);
}

void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
void ExpansionInterfaceManager::RegisterMMIO(MMIO::Mapping* mmio, u32 base)
{
auto& state = Core::System::GetInstance().GetExpansionInterfaceState().GetData();
for (int i = 0; i < MAX_EXI_CHANNELS; ++i)
{
DEBUG_ASSERT(state.channels[i] != nullptr);
DEBUG_ASSERT(m_channels[i] != nullptr);
// Each channel has 5 32 bit registers assigned to it. We offset the
// base that we give to each channel for registration.
//
// Be careful: this means the base is no longer aligned on a page
// boundary and using "base | FOO" is not valid!
state.channels[i]->RegisterMMIO(mmio, base + 5 * 4 * i);
m_channels[i]->RegisterMMIO(mmio, base + 5 * 4 * i);
}
}

static void ChangeDeviceCallback(Core::System& system, u64 userdata, s64 cyclesLate)
void ExpansionInterfaceManager::ChangeDeviceCallback(Core::System& system, u64 userdata,
s64 cycles_late)
{
u8 channel = (u8)(userdata >> 32);
u8 type = (u8)(userdata >> 16);
u8 num = (u8)userdata;

auto& state = system.GetExpansionInterfaceState().GetData();
state.channels.at(channel)->AddDevice(static_cast<EXIDeviceType>(type), num);
system.GetExpansionInterface().m_channels.at(channel)->AddDevice(static_cast<EXIDeviceType>(type),
num);
}

void ChangeDevice(Slot slot, EXIDeviceType device_type, CoreTiming::FromThread from_thread)
void ExpansionInterfaceManager::ChangeDevice(Slot slot, EXIDeviceType device_type,
CoreTiming::FromThread from_thread)
{
ChangeDevice(SlotToEXIChannel(slot), SlotToEXIDevice(slot), device_type, from_thread);
}

void ChangeDevice(u8 channel, u8 device_num, EXIDeviceType device_type,
CoreTiming::FromThread from_thread)
void ExpansionInterfaceManager::ChangeDevice(u8 channel, u8 device_num, EXIDeviceType device_type,
CoreTiming::FromThread from_thread)
{
// Let the hardware see no device for 1 second
auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();
auto& state = system.GetExpansionInterfaceState().GetData();
core_timing.ScheduleEvent(0, state.event_type_change_device,
auto& core_timing = m_system.GetCoreTiming();
core_timing.ScheduleEvent(0, m_event_type_change_device,
((u64)channel << 32) | ((u64)EXIDeviceType::None << 16) | device_num,
from_thread);
core_timing.ScheduleEvent(SystemTimers::GetTicksPerSecond(), state.event_type_change_device,
core_timing.ScheduleEvent(SystemTimers::GetTicksPerSecond(), m_event_type_change_device,
((u64)channel << 32) | ((u64)device_type << 16) | device_num,
from_thread);
}

CEXIChannel* GetChannel(u32 index)
CEXIChannel* ExpansionInterfaceManager::GetChannel(u32 index)
{
auto& state = Core::System::GetInstance().GetExpansionInterfaceState().GetData();
return state.channels.at(index).get();
return m_channels.at(index).get();
}

IEXIDevice* GetDevice(Slot slot)
IEXIDevice* ExpansionInterfaceManager::GetDevice(Slot slot)
{
auto& state = Core::System::GetInstance().GetExpansionInterfaceState().GetData();
return state.channels.at(SlotToEXIChannel(slot))->GetDevice(1 << SlotToEXIDevice(slot));
return m_channels.at(SlotToEXIChannel(slot))->GetDevice(1 << SlotToEXIDevice(slot));
}

void UpdateInterrupts()
void ExpansionInterfaceManager::UpdateInterrupts()
{
// Interrupts are mapped a bit strangely:
// Channel 0 Device 0 generates interrupt on channel 0
// Channel 0 Device 2 generates interrupt on channel 2
// Channel 1 Device 0 generates interrupt on channel 1
auto& system = Core::System::GetInstance();
auto& state = system.GetExpansionInterfaceState().GetData();
state.channels[2]->SetEXIINT(state.channels[0]->GetDevice(4)->IsInterruptSet());
m_channels[2]->SetEXIINT(m_channels[0]->GetDevice(4)->IsInterruptSet());

bool causeInt = false;
for (auto& channel : state.channels)
for (auto& channel : m_channels)
causeInt |= channel->IsCausingInterrupt();

system.GetProcessorInterface().SetInterrupt(ProcessorInterface::INT_CAUSE_EXI, causeInt);
m_system.GetProcessorInterface().SetInterrupt(ProcessorInterface::INT_CAUSE_EXI, causeInt);
}

static void UpdateInterruptsCallback(Core::System& system, u64 userdata, s64 cycles_late)
void ExpansionInterfaceManager::UpdateInterruptsCallback(Core::System& system, u64 userdata,
s64 cycles_late)
{
UpdateInterrupts();
system.GetExpansionInterface().UpdateInterrupts();
}

void ScheduleUpdateInterrupts(CoreTiming::FromThread from, int cycles_late)
void ExpansionInterfaceManager::ScheduleUpdateInterrupts(CoreTiming::FromThread from,
int cycles_late)
{
auto& system = Core::System::GetInstance();
auto& state = Core::System::GetInstance().GetExpansionInterfaceState().GetData();
system.GetCoreTiming().ScheduleEvent(cycles_late, state.event_type_update_interrupts, 0, from);
m_system.GetCoreTiming().ScheduleEvent(cycles_late, m_event_type_update_interrupts, 0, from);
}

} // namespace ExpansionInterface
76 changes: 45 additions & 31 deletions Source/Core/Core/HW/EXI/EXI.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#pragma once

#include <array>
#include <initializer_list>
#include <memory>

Expand All @@ -13,34 +14,22 @@
class PointerWrap;
struct Sram;

namespace Core
{
class System;
}
namespace CoreTiming
{
struct EventType;
enum class FromThread;
}
} // namespace CoreTiming
namespace MMIO
{
class Mapping;
}

namespace ExpansionInterface
{
class ExpansionInterfaceState
{
public:
ExpansionInterfaceState();
ExpansionInterfaceState(const ExpansionInterfaceState&) = delete;
ExpansionInterfaceState(ExpansionInterfaceState&&) = delete;
ExpansionInterfaceState& operator=(const ExpansionInterfaceState&) = delete;
ExpansionInterfaceState& operator=(ExpansionInterfaceState&&) = delete;
~ExpansionInterfaceState();

struct Data;
Data& GetData() { return *m_data; }

private:
std::unique_ptr<Data> m_data;
};

class CEXIChannel;
class IEXIDevice;
enum class EXIDeviceType : int;
Expand Down Expand Up @@ -70,24 +59,49 @@ constexpr bool IsMemcardSlot(Slot slot)
u8 SlotToEXIChannel(Slot slot);
u8 SlotToEXIDevice(Slot slot);

void Init(const Sram* override_sram);
void Shutdown();
void DoState(PointerWrap& p);
void PauseAndLock(bool doLock, bool unpauseOnUnlock);
class ExpansionInterfaceManager
{
public:
explicit ExpansionInterfaceManager(Core::System& system);
ExpansionInterfaceManager(const ExpansionInterfaceManager&) = delete;
ExpansionInterfaceManager(ExpansionInterfaceManager&&) = delete;
ExpansionInterfaceManager& operator=(const ExpansionInterfaceManager&) = delete;
ExpansionInterfaceManager& operator=(ExpansionInterfaceManager&&) = delete;
~ExpansionInterfaceManager();

void Init(const Sram* override_sram);
void Shutdown();
void DoState(PointerWrap& p);
void PauseAndLock(bool doLock, bool unpauseOnUnlock);

void RegisterMMIO(MMIO::Mapping* mmio, u32 base);

void UpdateInterrupts();
void ScheduleUpdateInterrupts(CoreTiming::FromThread from, int cycles_late);

void RegisterMMIO(MMIO::Mapping* mmio, u32 base);
void ChangeDevice(Slot slot, EXIDeviceType device_type,
CoreTiming::FromThread from_thread = CoreTiming::FromThread::NON_CPU);
void ChangeDevice(u8 channel, u8 device_num, EXIDeviceType device_type,
CoreTiming::FromThread from_thread = CoreTiming::FromThread::NON_CPU);

void UpdateInterrupts();
void ScheduleUpdateInterrupts(CoreTiming::FromThread from, int cycles_late);
CEXIChannel* GetChannel(u32 index);
IEXIDevice* GetDevice(Slot slot);

void ChangeDevice(Slot slot, EXIDeviceType device_type,
CoreTiming::FromThread from_thread = CoreTiming::FromThread::NON_CPU);
void ChangeDevice(u8 channel, u8 device_num, EXIDeviceType device_type,
CoreTiming::FromThread from_thread = CoreTiming::FromThread::NON_CPU);
private:
void AddMemoryCard(Slot slot);

static void ChangeDeviceCallback(Core::System& system, u64 userdata, s64 cycles_late);
static void UpdateInterruptsCallback(Core::System& system, u64 userdata, s64 cycles_late);

CoreTiming::EventType* m_event_type_change_device = nullptr;
CoreTiming::EventType* m_event_type_update_interrupts = nullptr;

CEXIChannel* GetChannel(u32 index);
IEXIDevice* GetDevice(Slot slot);
std::array<std::unique_ptr<CEXIChannel>, MAX_EXI_CHANNELS> m_channels;

bool m_using_overridden_sram = false;

Core::System& m_system;
};
} // namespace ExpansionInterface

template <>
Expand Down
Loading

0 comments on commit 7b5c989

Please sign in to comment.