summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authorBonta <40473493+Bonta0@users.noreply.github.com>2021-07-04 13:15:37 +0200
committerBonta <40473493+Bonta0@users.noreply.github.com>2021-07-13 16:42:57 +0200
commitd0f0b4c0e054b2177e524fba274dbefa98dfa7b7 (patch)
treee032f34efd7a718b1822a53c7b8db1c6b006cfdd /Source/Core
parent9a22ff653f089057f6990ea32dfd33d96a158698 (diff)
SI: Implement GBAEmu device
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/AudioCommon/AudioCommon.cpp3
-rw-r--r--Source/Core/Core/CMakeLists.txt2
-rw-r--r--Source/Core/Core/HW/SI/SI.cpp2
-rw-r--r--Source/Core/Core/HW/SI/SI_Device.cpp12
-rw-r--r--Source/Core/Core/HW/SI/SI_Device.h1
-rw-r--r--Source/Core/Core/HW/SI/SI_DeviceGBAEmu.cpp167
-rw-r--r--Source/Core/Core/HW/SI/SI_DeviceGBAEmu.h49
-rw-r--r--Source/Core/Core/State.cpp2
-rw-r--r--Source/Core/DolphinLib.props2
9 files changed, 237 insertions, 3 deletions
diff --git a/Source/Core/AudioCommon/AudioCommon.cpp b/Source/Core/AudioCommon/AudioCommon.cpp
index cfa5383c7c..6623b5ad8b 100644
--- a/Source/Core/AudioCommon/AudioCommon.cpp
+++ b/Source/Core/AudioCommon/AudioCommon.cpp
@@ -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);
diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt
index 65eb857982..0ae84e2bdc 100644
--- a/Source/Core/Core/CMakeLists.txt
+++ b/Source/Core/Core/CMakeLists.txt
@@ -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)
diff --git a/Source/Core/Core/HW/SI/SI.cpp b/Source/Core/Core/HW/SI/SI.cpp
index 14e586fc05..caaa95cbae 100644
--- a/Source/Core/Core/HW/SI/SI.cpp
+++ b/Source/Core/Core/HW/SI/SI.cpp
@@ -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();
diff --git a/Source/Core/Core/HW/SI/SI_Device.cpp b/Source/Core/Core/HW/SI/SI_Device.cpp
index 401b1178a7..fa823ff8ad 100644
--- a/Source/Core/Core/HW/SI/SI_Device.cpp
+++ b/Source/Core/Core/HW/SI/SI_Device.cpp
@@ -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);
diff --git a/Source/Core/Core/HW/SI/SI_Device.h b/Source/Core/Core/HW/SI/SI_Device.h
index c2ae9bef87..d109432b90 100644
--- a/Source/Core/Core/HW/SI/SI_Device.h
+++ b/Source/Core/Core/HW/SI/SI_Device.h
@@ -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,
};
diff --git a/Source/Core/Core/HW/SI/SI_DeviceGBAEmu.cpp b/Source/Core/Core/HW/SI/SI_DeviceGBAEmu.cpp
new file mode 100644
index 0000000000..aaf971b45e
--- /dev/null
+++ b/Source/Core/Core/HW/SI/SI_DeviceGBAEmu.cpp
@@ -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
diff --git a/Source/Core/Core/HW/SI/SI_DeviceGBAEmu.h b/Source/Core/Core/HW/SI/SI_DeviceGBAEmu.h
new file mode 100644
index 0000000000..d19c43e27b
--- /dev/null
+++ b/Source/Core/Core/HW/SI/SI_DeviceGBAEmu.h
@@ -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
diff --git a/Source/Core/Core/State.cpp b/Source/Core/Core/State.cpp
index 5d5f6e9d33..77e31e1ac0 100644
--- a/Source/Core/Core/State.cpp
+++ b/Source/Core/Core/State.cpp
@@ -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,
diff --git a/Source/Core/DolphinLib.props b/Source/Core/DolphinLib.props
index 7835689d55..0f0dfe227b 100644
--- a/Source/Core/DolphinLib.props
+++ b/Source/Core/DolphinLib.props
@@ -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" />