mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-02-09 22:18:58 +01:00
SI: Implement GBAEmu device
This commit is contained in:
parent
9a22ff653f
commit
d0f0b4c0e0
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
|
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;
|
||||
|
||||
// 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,
|
||||
|
@ -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" />
|
||||
|
Loading…
x
Reference in New Issue
Block a user