SI: Implement GBAEmu device

This commit is contained in:
Bonta 2021-07-04 13:15:37 +02:00
parent 9a22ff653f
commit d0f0b4c0e0
9 changed files with 237 additions and 3 deletions

View File

@ -68,7 +68,8 @@ void InitSoundStream()
void PostInitSoundStream()
{
// This needs to be called after AudioInterface::Init where input sample rates are set
// This needs to be called after AudioInterface::Init and SerialInterface::Init (for GBA devices)
// where input sample rates are set
UpdateSoundStream();
SetSoundStreamRunning(true);

View File

@ -624,6 +624,8 @@ if(USE_MGBA)
target_sources(core PRIVATE
HW/GBACore.cpp
HW/GBACore.h
HW/SI/SI_DeviceGBAEmu.cpp
HW/SI/SI_DeviceGBAEmu.h
)
target_link_libraries(core PUBLIC mGBA::mgba)
target_compile_definitions(core PUBLIC -DHAS_LIBMGBA)

View File

@ -707,7 +707,7 @@ void UpdateDevices()
SIDevices GetDeviceType(int channel)
{
if (channel < 0 || channel > 3)
if (channel < 0 || channel >= MAX_SI_CHANNELS || !s_channel[channel].device)
return SIDEVICE_NONE;
return s_channel[channel].device->GetDeviceType();

View File

@ -13,8 +13,12 @@
#include "Common/CommonTypes.h"
#include "Common/Logging/Log.h"
#include "Common/MsgHandler.h"
#include "Core/HW/SI/SI_DeviceDanceMat.h"
#include "Core/HW/SI/SI_DeviceGBA.h"
#ifdef HAS_LIBMGBA
#include "Core/HW/SI/SI_DeviceGBAEmu.h"
#endif
#include "Core/HW/SI/SI_DeviceGCAdapter.h"
#include "Core/HW/SI/SI_DeviceGCController.h"
#include "Core/HW/SI/SI_DeviceGCSteeringWheel.h"
@ -187,6 +191,14 @@ std::unique_ptr<ISIDevice> SIDevice_Create(const SIDevices device, const int por
case SIDEVICE_GC_GBA:
return std::make_unique<CSIDevice_GBA>(device, port_number);
case SIDEVICE_GC_GBA_EMULATED:
#ifdef HAS_LIBMGBA
return std::make_unique<CSIDevice_GBAEmu>(device, port_number);
#else
PanicAlertT("Error: This build does not support emulated GBA controllers");
return std::make_unique<CSIDevice_Null>(device, port_number);
#endif
case SIDEVICE_GC_KEYBOARD:
return std::make_unique<CSIDevice_Keyboard>(device, port_number);

View File

@ -93,6 +93,7 @@ enum SIDevices : int
// It's kept here so that values below will stay constant.
SIDEVICE_AM_BASEBOARD,
SIDEVICE_WIIU_ADAPTER,
SIDEVICE_GC_GBA_EMULATED,
// Not a valid device. Used for checking whether enum values are valid.
SIDEVICE_COUNT,
};

View File

@ -0,0 +1,167 @@
// Copyright 2021 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <vector>
#include "Common/ChunkFile.h"
#include "Common/CommonTypes.h"
#include "Common/Logging/Log.h"
#include "Common/Swap.h"
#include "Core/Core.h"
#include "Core/CoreTiming.h"
#include "Core/HW/GBACore.h"
#include "Core/HW/GBAPad.h"
#include "Core/HW/SI/SI.h"
#include "Core/HW/SI/SI_DeviceGBAEmu.h"
#include "Core/HW/SI/SI_DeviceGCController.h"
#include "Core/HW/SystemTimers.h"
#include "Core/Host.h"
#include "Core/NetPlayProto.h"
namespace SerialInterface
{
static s64 GetSyncInterval()
{
return SystemTimers::GetTicksPerSecond() / 1000;
}
CSIDevice_GBAEmu::CSIDevice_GBAEmu(SIDevices device, int device_number)
: ISIDevice(device, device_number)
{
m_core = std::make_shared<HW::GBA::Core>(m_device_number);
m_core->Start(CoreTiming::GetTicks());
m_gbahost = Host_CreateGBAHost(m_core);
m_core->SetHost(m_gbahost);
ScheduleEvent(m_device_number, GetSyncInterval());
}
CSIDevice_GBAEmu::~CSIDevice_GBAEmu()
{
RemoveEvent(m_device_number);
m_core->Stop();
m_gbahost.reset();
m_core.reset();
}
int CSIDevice_GBAEmu::RunBuffer(u8* buffer, int request_length)
{
switch (m_next_action)
{
case NextAction::SendCommand:
{
#ifdef _DEBUG
NOTICE_LOG_FMT(SERIALINTERFACE, "{} cmd {:02x} [> {:02x}{:02x}{:02x}{:02x}]", m_device_number,
buffer[0], buffer[1], buffer[2], buffer[3], buffer[4]);
#endif
m_last_cmd = static_cast<EBufferCommands>(buffer[0]);
m_timestamp_sent = CoreTiming::GetTicks();
m_core->SendJoybusCommand(m_timestamp_sent, TransferInterval(), buffer, m_keys);
RemoveEvent(m_device_number);
ScheduleEvent(m_device_number, TransferInterval() + GetSyncInterval());
for (int i = 0; i < MAX_SI_CHANNELS; ++i)
{
if (i == m_device_number || SerialInterface::GetDeviceType(i) != GetDeviceType())
continue;
RemoveEvent(i);
ScheduleEvent(i, 0, static_cast<u64>(TransferInterval()));
}
m_next_action = NextAction::WaitTransferTime;
[[fallthrough]];
}
case NextAction::WaitTransferTime:
{
int elapsed_time = static_cast<int>(CoreTiming::GetTicks() - m_timestamp_sent);
// Tell SI to ask again after TransferInterval() cycles
if (TransferInterval() > elapsed_time)
return 0;
m_next_action = NextAction::ReceiveResponse;
[[fallthrough]];
}
case NextAction::ReceiveResponse:
{
m_next_action = NextAction::SendCommand;
std::vector<u8> response = m_core->GetJoybusResponse();
if (response.empty())
return -1;
std::copy(response.begin(), response.end(), buffer);
#ifdef _DEBUG
const Common::Log::LOG_LEVELS log_level =
(m_last_cmd == EBufferCommands::CMD_STATUS || m_last_cmd == EBufferCommands::CMD_RESET) ?
Common::Log::LERROR :
Common::Log::LWARNING;
GENERIC_LOG_FMT(Common::Log::SERIALINTERFACE, log_level,
"{} [< {:02x}{:02x}{:02x}{:02x}{:02x}] ({})",
m_device_number, buffer[0], buffer[1], buffer[2], buffer[3], buffer[4],
response.size());
#endif
return static_cast<int>(response.size());
}
}
// This should never happen, but appease MSVC which thinks it might.
ERROR_LOG_FMT(SERIALINTERFACE, "Unknown state {}\n", m_next_action);
return -1;
}
int CSIDevice_GBAEmu::TransferInterval()
{
return SIDevice_GetGBATransferTime(m_last_cmd);
}
bool CSIDevice_GBAEmu::GetData(u32& hi, u32& low)
{
GCPadStatus pad_status{};
if (!NetPlay::IsNetPlayRunning())
pad_status = Pad::GetGBAStatus(m_device_number);
SerialInterface::CSIDevice_GCController::HandleMoviePadStatus(m_device_number, &pad_status);
static constexpr std::array<PadButton, 10> buttons_map = {
PadButton::PAD_BUTTON_A, // A
PadButton::PAD_BUTTON_B, // B
PadButton::PAD_TRIGGER_Z, // Select
PadButton::PAD_BUTTON_START, // Start
PadButton::PAD_BUTTON_RIGHT, // Right
PadButton::PAD_BUTTON_LEFT, // Left
PadButton::PAD_BUTTON_UP, // Up
PadButton::PAD_BUTTON_DOWN, // Down
PadButton::PAD_TRIGGER_R, // R
PadButton::PAD_TRIGGER_L, // L
};
m_keys = 0;
for (size_t i = 0; i < buttons_map.size(); ++i)
m_keys |= static_cast<u16>(static_cast<bool>((pad_status.button & buttons_map[i]))) << i;
// Use X button as a reset signal for NetPlay/Movies
if (pad_status.button & PadButton::PAD_BUTTON_X)
m_core->Reset();
return false;
}
void CSIDevice_GBAEmu::SendCommand(u32 command, u8 poll)
{
}
void CSIDevice_GBAEmu::DoState(PointerWrap& p)
{
p.Do(m_next_action);
p.Do(m_last_cmd);
p.Do(m_timestamp_sent);
p.Do(m_keys);
m_core->DoState(p);
}
void CSIDevice_GBAEmu::OnEvent(u64 userdata, s64 cycles_late)
{
m_core->SendJoybusCommand(CoreTiming::GetTicks() + userdata, 0, nullptr, m_keys);
ScheduleEvent(m_device_number, userdata + GetSyncInterval());
}
} // namespace SerialInterface

View File

@ -0,0 +1,49 @@
// Copyright 2021 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <memory>
#include "Common/CommonTypes.h"
#include "Core/HW/SI/SI_Device.h"
namespace HW::GBA
{
class Core;
} // namespace HW::GBA
class GBAHostInterface;
namespace SerialInterface
{
class CSIDevice_GBAEmu : public ISIDevice
{
public:
CSIDevice_GBAEmu(SIDevices device, int device_number);
~CSIDevice_GBAEmu();
int RunBuffer(u8* buffer, int request_length) override;
int TransferInterval() override;
bool GetData(u32& hi, u32& low) override;
void SendCommand(u32 command, u8 poll) override;
void DoState(PointerWrap& p) override;
void OnEvent(u64 userdata, s64 cycles_late) override;
private:
enum class NextAction
{
SendCommand,
WaitTransferTime,
ReceiveResponse
};
NextAction m_next_action = NextAction::SendCommand;
EBufferCommands m_last_cmd{};
u64 m_timestamp_sent = 0;
u16 m_keys = 0;
std::shared_ptr<HW::GBA::Core> m_core;
std::shared_ptr<GBAHostInterface> m_gbahost;
};
} // namespace SerialInterface

View File

@ -73,7 +73,7 @@ static Common::Event g_compressAndDumpStateSyncEvent;
static std::thread g_save_thread;
// Don't forget to increase this after doing changes on the savestate system
constexpr u32 STATE_VERSION = 132; // Last changed in PR 9532
constexpr u32 STATE_VERSION = 133; // Last changed in PR 9600
// Maps savestate versions to Dolphin versions.
// Versions after 42 don't need to be added to this list,

View File

@ -287,6 +287,7 @@
<ClInclude Include="Core\HW\SI\SI_Device.h" />
<ClInclude Include="Core\HW\SI\SI_DeviceDanceMat.h" />
<ClInclude Include="Core\HW\SI\SI_DeviceGBA.h" />
<ClInclude Include="Core\HW\SI\SI_DeviceGBAEmu.h" />
<ClInclude Include="Core\HW\SI\SI_DeviceGCAdapter.h" />
<ClInclude Include="Core\HW\SI\SI_DeviceGCController.h" />
<ClInclude Include="Core\HW\SI\SI_DeviceGCSteeringWheel.h" />
@ -868,6 +869,7 @@
<ClCompile Include="Core\HW\SI\SI_Device.cpp" />
<ClCompile Include="Core\HW\SI\SI_DeviceDanceMat.cpp" />
<ClCompile Include="Core\HW\SI\SI_DeviceGBA.cpp" />
<ClCompile Include="Core\HW\SI\SI_DeviceGBAEmu.cpp" />
<ClCompile Include="Core\HW\SI\SI_DeviceGCAdapter.cpp" />
<ClCompile Include="Core\HW\SI\SI_DeviceGCController.cpp" />
<ClCompile Include="Core\HW\SI\SI_DeviceGCSteeringWheel.cpp" />