Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HW: Refactor ExpansionInterface and MemoryInterface to classes. #11639

Merged
merged 2 commits into from Mar 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion Source/Core/Core/Core.cpp
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
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
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