mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-02-14 00:09:24 +01:00
SI: Implement GBAEmu device
This commit is contained in:
parent
9a22ff653f
commit
d0f0b4c0e0
@ -68,7 +68,8 @@ void InitSoundStream()
|
|||||||
|
|
||||||
void PostInitSoundStream()
|
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();
|
UpdateSoundStream();
|
||||||
SetSoundStreamRunning(true);
|
SetSoundStreamRunning(true);
|
||||||
|
|
||||||
|
@ -624,6 +624,8 @@ if(USE_MGBA)
|
|||||||
target_sources(core PRIVATE
|
target_sources(core PRIVATE
|
||||||
HW/GBACore.cpp
|
HW/GBACore.cpp
|
||||||
HW/GBACore.h
|
HW/GBACore.h
|
||||||
|
HW/SI/SI_DeviceGBAEmu.cpp
|
||||||
|
HW/SI/SI_DeviceGBAEmu.h
|
||||||
)
|
)
|
||||||
target_link_libraries(core PUBLIC mGBA::mgba)
|
target_link_libraries(core PUBLIC mGBA::mgba)
|
||||||
target_compile_definitions(core PUBLIC -DHAS_LIBMGBA)
|
target_compile_definitions(core PUBLIC -DHAS_LIBMGBA)
|
||||||
|
@ -707,7 +707,7 @@ void UpdateDevices()
|
|||||||
|
|
||||||
SIDevices GetDeviceType(int channel)
|
SIDevices GetDeviceType(int channel)
|
||||||
{
|
{
|
||||||
if (channel < 0 || channel > 3)
|
if (channel < 0 || channel >= MAX_SI_CHANNELS || !s_channel[channel].device)
|
||||||
return SIDEVICE_NONE;
|
return SIDEVICE_NONE;
|
||||||
|
|
||||||
return s_channel[channel].device->GetDeviceType();
|
return s_channel[channel].device->GetDeviceType();
|
||||||
|
@ -13,8 +13,12 @@
|
|||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
|
#include "Common/MsgHandler.h"
|
||||||
#include "Core/HW/SI/SI_DeviceDanceMat.h"
|
#include "Core/HW/SI/SI_DeviceDanceMat.h"
|
||||||
#include "Core/HW/SI/SI_DeviceGBA.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_DeviceGCAdapter.h"
|
||||||
#include "Core/HW/SI/SI_DeviceGCController.h"
|
#include "Core/HW/SI/SI_DeviceGCController.h"
|
||||||
#include "Core/HW/SI/SI_DeviceGCSteeringWheel.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:
|
case SIDEVICE_GC_GBA:
|
||||||
return std::make_unique<CSIDevice_GBA>(device, port_number);
|
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:
|
case SIDEVICE_GC_KEYBOARD:
|
||||||
return std::make_unique<CSIDevice_Keyboard>(device, port_number);
|
return std::make_unique<CSIDevice_Keyboard>(device, port_number);
|
||||||
|
|
||||||
|
@ -93,6 +93,7 @@ enum SIDevices : int
|
|||||||
// It's kept here so that values below will stay constant.
|
// It's kept here so that values below will stay constant.
|
||||||
SIDEVICE_AM_BASEBOARD,
|
SIDEVICE_AM_BASEBOARD,
|
||||||
SIDEVICE_WIIU_ADAPTER,
|
SIDEVICE_WIIU_ADAPTER,
|
||||||
|
SIDEVICE_GC_GBA_EMULATED,
|
||||||
// Not a valid device. Used for checking whether enum values are valid.
|
// Not a valid device. Used for checking whether enum values are valid.
|
||||||
SIDEVICE_COUNT,
|
SIDEVICE_COUNT,
|
||||||
};
|
};
|
||||||
|
167
Source/Core/Core/HW/SI/SI_DeviceGBAEmu.cpp
Normal file
167
Source/Core/Core/HW/SI/SI_DeviceGBAEmu.cpp
Normal 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
|
49
Source/Core/Core/HW/SI/SI_DeviceGBAEmu.h
Normal file
49
Source/Core/Core/HW/SI/SI_DeviceGBAEmu.h
Normal 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
|
@ -73,7 +73,7 @@ static Common::Event g_compressAndDumpStateSyncEvent;
|
|||||||
static std::thread g_save_thread;
|
static std::thread g_save_thread;
|
||||||
|
|
||||||
// Don't forget to increase this after doing changes on the savestate system
|
// 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.
|
// Maps savestate versions to Dolphin versions.
|
||||||
// Versions after 42 don't need to be added to this list,
|
// Versions after 42 don't need to be added to this list,
|
||||||
|
@ -287,6 +287,7 @@
|
|||||||
<ClInclude Include="Core\HW\SI\SI_Device.h" />
|
<ClInclude Include="Core\HW\SI\SI_Device.h" />
|
||||||
<ClInclude Include="Core\HW\SI\SI_DeviceDanceMat.h" />
|
<ClInclude Include="Core\HW\SI\SI_DeviceDanceMat.h" />
|
||||||
<ClInclude Include="Core\HW\SI\SI_DeviceGBA.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_DeviceGCAdapter.h" />
|
||||||
<ClInclude Include="Core\HW\SI\SI_DeviceGCController.h" />
|
<ClInclude Include="Core\HW\SI\SI_DeviceGCController.h" />
|
||||||
<ClInclude Include="Core\HW\SI\SI_DeviceGCSteeringWheel.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_Device.cpp" />
|
||||||
<ClCompile Include="Core\HW\SI\SI_DeviceDanceMat.cpp" />
|
<ClCompile Include="Core\HW\SI\SI_DeviceDanceMat.cpp" />
|
||||||
<ClCompile Include="Core\HW\SI\SI_DeviceGBA.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_DeviceGCAdapter.cpp" />
|
||||||
<ClCompile Include="Core\HW\SI\SI_DeviceGCController.cpp" />
|
<ClCompile Include="Core\HW\SI\SI_DeviceGCController.cpp" />
|
||||||
<ClCompile Include="Core\HW\SI\SI_DeviceGCSteeringWheel.cpp" />
|
<ClCompile Include="Core\HW\SI\SI_DeviceGCSteeringWheel.cpp" />
|
||||||
|
Loading…
x
Reference in New Issue
Block a user