Merge pull request #1720 from ggrtk/multitap
Multitap: Add option to enable only on port 2
This commit is contained in:
commit
3f698d6ed9
|
@ -7,9 +7,8 @@
|
||||||
#include "pad.h"
|
#include "pad.h"
|
||||||
Log_SetChannel(Multitap);
|
Log_SetChannel(Multitap);
|
||||||
|
|
||||||
Multitap::Multitap(u32 index) : m_index(index)
|
Multitap::Multitap()
|
||||||
{
|
{
|
||||||
m_index = index;
|
|
||||||
Reset();
|
Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,6 +23,16 @@ void Multitap::Reset()
|
||||||
m_transfer_buffer.fill(0xFF);
|
m_transfer_buffer.fill(0xFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Multitap::SetEnable(bool enable, u32 base_index)
|
||||||
|
{
|
||||||
|
if (m_enabled != enable || m_base_index != base_index)
|
||||||
|
{
|
||||||
|
m_enabled = enable;
|
||||||
|
m_base_index = base_index;
|
||||||
|
Reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool Multitap::DoState(StateWrapper& sw)
|
bool Multitap::DoState(StateWrapper& sw)
|
||||||
{
|
{
|
||||||
sw.Do(&m_transfer_state);
|
sw.Do(&m_transfer_state);
|
||||||
|
@ -48,19 +57,9 @@ void Multitap::ResetTransferState()
|
||||||
// Controller and memory card transfer resets are handled in the Pad class
|
// Controller and memory card transfer resets are handled in the Pad class
|
||||||
}
|
}
|
||||||
|
|
||||||
Controller* Multitap::GetControllerForSlot(u32 slot) const
|
|
||||||
{
|
|
||||||
return g_pad.GetController(m_index * 4 + slot);
|
|
||||||
}
|
|
||||||
|
|
||||||
MemoryCard* Multitap::GetMemoryCardForSlot(u32 slot) const
|
|
||||||
{
|
|
||||||
return g_pad.GetMemoryCard(m_index * 4 + slot);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Multitap::TransferController(u32 slot, const u8 data_in, u8* data_out) const
|
bool Multitap::TransferController(u32 slot, const u8 data_in, u8* data_out) const
|
||||||
{
|
{
|
||||||
Controller* const selected_controller = GetControllerForSlot(slot);
|
Controller* const selected_controller = g_pad.GetController(m_base_index + slot);
|
||||||
if (!selected_controller)
|
if (!selected_controller)
|
||||||
{
|
{
|
||||||
*data_out = 0xFF;
|
*data_out = 0xFF;
|
||||||
|
@ -72,7 +71,7 @@ bool Multitap::TransferController(u32 slot, const u8 data_in, u8* data_out) cons
|
||||||
|
|
||||||
bool Multitap::TransferMemoryCard(u32 slot, const u8 data_in, u8* data_out) const
|
bool Multitap::TransferMemoryCard(u32 slot, const u8 data_in, u8* data_out) const
|
||||||
{
|
{
|
||||||
MemoryCard* const selected_memcard = GetMemoryCardForSlot(slot);
|
MemoryCard* const selected_memcard = g_pad.GetMemoryCard(m_base_index + slot);
|
||||||
if (!selected_memcard)
|
if (!selected_memcard)
|
||||||
{
|
{
|
||||||
*data_out = 0xFF;
|
*data_out = 0xFF;
|
||||||
|
@ -198,7 +197,7 @@ bool Multitap::Transfer(const u8 data_in, u8* data_out)
|
||||||
|
|
||||||
case TransferState::SingleController:
|
case TransferState::SingleController:
|
||||||
{
|
{
|
||||||
// TODO: Check if the transfer buffer get wiped when transitioning to/from this mode
|
// TODO: Check if the transfer buffer gets wiped when transitioning to/from this mode
|
||||||
|
|
||||||
ack = TransferController(m_selected_slot, data_in, data_out);
|
ack = TransferController(m_selected_slot, data_in, data_out);
|
||||||
|
|
||||||
|
|
|
@ -8,26 +8,23 @@
|
||||||
class Multitap final
|
class Multitap final
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Multitap(u32 index);
|
Multitap();
|
||||||
|
|
||||||
void Reset();
|
void Reset();
|
||||||
|
|
||||||
ALWAYS_INLINE void SetEnable(bool enable) { m_enabled = enable; };
|
void SetEnable(bool enable, u32 base_index);
|
||||||
ALWAYS_INLINE bool IsEnabled() const { return m_enabled; };
|
ALWAYS_INLINE bool IsEnabled() const { return m_enabled; };
|
||||||
|
|
||||||
bool DoState(StateWrapper& sw);
|
bool DoState(StateWrapper& sw);
|
||||||
|
|
||||||
void ResetTransferState();
|
void ResetTransferState();
|
||||||
bool Transfer(const u8 data_in, u8* data_out);
|
bool Transfer(const u8 data_in, u8* data_out);
|
||||||
ALWAYS_INLINE bool IsReadingMemoryCard() { return m_enabled && m_transfer_state == TransferState::MemoryCard; };
|
ALWAYS_INLINE bool IsReadingMemoryCard() { return IsEnabled() && m_transfer_state == TransferState::MemoryCard; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ALWAYS_INLINE static constexpr u8 GetMultitapIDByte() { return 0x80; };
|
ALWAYS_INLINE static constexpr u8 GetMultitapIDByte() { return 0x80; };
|
||||||
ALWAYS_INLINE static constexpr u8 GetStatusByte() { return 0x5A; };
|
ALWAYS_INLINE static constexpr u8 GetStatusByte() { return 0x5A; };
|
||||||
|
|
||||||
Controller* GetControllerForSlot(u32 slot) const;
|
|
||||||
MemoryCard* GetMemoryCardForSlot(u32 slot) const;
|
|
||||||
|
|
||||||
bool TransferController(u32 slot, const u8 data_in, u8* data_out) const;
|
bool TransferController(u32 slot, const u8 data_in, u8* data_out) const;
|
||||||
bool TransferMemoryCard(u32 slot, const u8 data_in, u8* data_out) const;
|
bool TransferMemoryCard(u32 slot, const u8 data_in, u8* data_out) const;
|
||||||
|
|
||||||
|
@ -51,6 +48,6 @@ private:
|
||||||
|
|
||||||
std::array<u8, 32> m_transfer_buffer{};
|
std::array<u8, 32> m_transfer_buffer{};
|
||||||
|
|
||||||
u32 m_index;
|
u32 m_base_index;
|
||||||
bool m_enabled = false;
|
bool m_enabled = false;
|
||||||
};
|
};
|
||||||
|
|
|
@ -247,15 +247,6 @@ void Pad::SetMemoryCard(u32 slot, std::unique_ptr<MemoryCard> dev)
|
||||||
m_memory_cards[slot] = std::move(dev);
|
m_memory_cards[slot] = std::move(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Pad::SetMultitapEnable(u32 port, bool enable)
|
|
||||||
{
|
|
||||||
if (m_multitaps[port].IsEnabled() != enable)
|
|
||||||
{
|
|
||||||
m_multitaps[port].SetEnable(enable);
|
|
||||||
m_multitaps[port].Reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 Pad::ReadRegister(u32 offset)
|
u32 Pad::ReadRegister(u32 offset)
|
||||||
{
|
{
|
||||||
switch (offset)
|
switch (offset)
|
||||||
|
|
|
@ -30,7 +30,6 @@ public:
|
||||||
void SetMemoryCard(u32 slot, std::unique_ptr<MemoryCard> dev);
|
void SetMemoryCard(u32 slot, std::unique_ptr<MemoryCard> dev);
|
||||||
|
|
||||||
Multitap* GetMultitap(u32 slot) { return &m_multitaps[slot]; };
|
Multitap* GetMultitap(u32 slot) { return &m_multitaps[slot]; };
|
||||||
void SetMultitapEnable(u32 port, bool enable);
|
|
||||||
|
|
||||||
u32 ReadRegister(u32 offset);
|
u32 ReadRegister(u32 offset);
|
||||||
void WriteRegister(u32 offset, u32 value);
|
void WriteRegister(u32 offset, u32 value);
|
||||||
|
@ -116,7 +115,7 @@ private:
|
||||||
std::array<std::unique_ptr<Controller>, NUM_CONTROLLER_AND_CARD_PORTS> m_controllers;
|
std::array<std::unique_ptr<Controller>, NUM_CONTROLLER_AND_CARD_PORTS> m_controllers;
|
||||||
std::array<std::unique_ptr<MemoryCard>, NUM_CONTROLLER_AND_CARD_PORTS> m_memory_cards;
|
std::array<std::unique_ptr<MemoryCard>, NUM_CONTROLLER_AND_CARD_PORTS> m_memory_cards;
|
||||||
|
|
||||||
std::array<Multitap, NUM_MULTITAPS> m_multitaps = {Multitap(0), Multitap(1)};
|
std::array<Multitap, NUM_MULTITAPS> m_multitaps;
|
||||||
|
|
||||||
std::unique_ptr<TimingEvent> m_transfer_event;
|
std::unique_ptr<TimingEvent> m_transfer_event;
|
||||||
State m_state = State::Idle;
|
State m_state = State::Idle;
|
||||||
|
|
|
@ -78,26 +78,32 @@ bool Settings::HasAnyPerGameMemoryCards() const
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Settings::IsMultitapEnabledOnPort(u32 port) const
|
std::array<TinyString, NUM_CONTROLLER_AND_CARD_PORTS> Settings::GeneratePortLabels() const
|
||||||
{
|
{
|
||||||
if (port < NUM_MULTITAPS)
|
static constexpr std::array<std::array<bool, NUM_MULTITAPS>, static_cast<size_t>(MultitapMode::Count)>
|
||||||
|
multitap_enabled_on_port = {{{false, false}, {true, false}, {false, true}, {true, true}}};
|
||||||
|
|
||||||
|
std::array<TinyString, NUM_CONTROLLER_AND_CARD_PORTS> labels;
|
||||||
|
|
||||||
|
u32 logical_port = 0;
|
||||||
|
for (u32 physical_port = 0; physical_port < NUM_MULTITAPS; physical_port++)
|
||||||
{
|
{
|
||||||
switch (multitap_mode)
|
if (multitap_enabled_on_port[static_cast<size_t>(multitap_mode)][physical_port])
|
||||||
{
|
{
|
||||||
case MultitapMode::Disabled:
|
for (u32 i = 0; i < 4; i++)
|
||||||
return false;
|
{
|
||||||
|
labels[logical_port] = TinyString::FromFormat("Port %u%c", physical_port + 1u, 'A' + i);
|
||||||
case MultitapMode::Port1Only:
|
logical_port++;
|
||||||
return port == 0u;
|
}
|
||||||
|
}
|
||||||
case MultitapMode::BothPorts:
|
else
|
||||||
return true;
|
{
|
||||||
|
labels[logical_port] = TinyString::FromFormat("Port %u", physical_port + 1u);
|
||||||
DefaultCaseIsUnreachable();
|
logical_port++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return labels;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Settings::CPUOverclockPercentToFraction(u32 percent, u32* numerator, u32* denominator)
|
void Settings::CPUOverclockPercentToFraction(u32 percent, u32* numerator, u32* denominator)
|
||||||
|
@ -877,10 +883,10 @@ const char* Settings::GetMemoryCardTypeDisplayName(MemoryCardType type)
|
||||||
return s_memory_card_type_display_names[static_cast<int>(type)];
|
return s_memory_card_type_display_names[static_cast<int>(type)];
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::array<const char*, 3> s_multitap_enable_mode_names = {{"Disabled", "Port1Only", "BothPorts"}};
|
static std::array<const char*, 4> s_multitap_enable_mode_names = {{"Disabled", "Port1Only", "Port2Only", "BothPorts"}};
|
||||||
static std::array<const char*, 3> s_multitap_enable_mode_display_names = {
|
static std::array<const char*, 4> s_multitap_enable_mode_display_names = {
|
||||||
{TRANSLATABLE("MultitapMode", "Disabled"), TRANSLATABLE("MultitapMode", "Enable on Port 1 only"),
|
{TRANSLATABLE("MultitapMode", "Disabled"), TRANSLATABLE("MultitapMode", "Enable on Port 1 only"),
|
||||||
TRANSLATABLE("MultitapMode", "Enable on Ports 1 and 2")}};
|
TRANSLATABLE("MultitapMode", "Enable on Port 2 only"), TRANSLATABLE("MultitapMode", "Enable on Ports 1 and 2")}};
|
||||||
|
|
||||||
std::optional<MultitapMode> Settings::ParseMultitapModeName(const char* str)
|
std::optional<MultitapMode> Settings::ParseMultitapModeName(const char* str)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "common/log.h"
|
#include "common/log.h"
|
||||||
|
#include "common/string.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
@ -219,6 +220,8 @@ struct Settings
|
||||||
|
|
||||||
MultitapMode multitap_mode = MultitapMode::Disabled;
|
MultitapMode multitap_mode = MultitapMode::Disabled;
|
||||||
|
|
||||||
|
std::array<TinyString, NUM_CONTROLLER_AND_CARD_PORTS> GeneratePortLabels() const;
|
||||||
|
|
||||||
LOGLEVEL log_level = LOGLEVEL_INFO;
|
LOGLEVEL log_level = LOGLEVEL_INFO;
|
||||||
std::string log_filter;
|
std::string log_filter;
|
||||||
bool log_to_console = false;
|
bool log_to_console = false;
|
||||||
|
@ -254,8 +257,6 @@ struct Settings
|
||||||
|
|
||||||
bool HasAnyPerGameMemoryCards() const;
|
bool HasAnyPerGameMemoryCards() const;
|
||||||
|
|
||||||
bool IsMultitapEnabledOnPort(u32 port) const;
|
|
||||||
|
|
||||||
static void CPUOverclockPercentToFraction(u32 percent, u32* numerator, u32* denominator);
|
static void CPUOverclockPercentToFraction(u32 percent, u32* numerator, u32* denominator);
|
||||||
static u32 CPUOverclockFractionToPercent(u32 numerator, u32 denominator);
|
static u32 CPUOverclockFractionToPercent(u32 numerator, u32 denominator);
|
||||||
|
|
||||||
|
|
|
@ -1861,22 +1861,29 @@ void UpdateMultitaps()
|
||||||
{
|
{
|
||||||
case MultitapMode::Disabled:
|
case MultitapMode::Disabled:
|
||||||
{
|
{
|
||||||
g_pad.SetMultitapEnable(0, false);
|
g_pad.GetMultitap(0)->SetEnable(false, 0);
|
||||||
g_pad.SetMultitapEnable(1, false);
|
g_pad.GetMultitap(1)->SetEnable(false, 0);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MultitapMode::Port1Only:
|
case MultitapMode::Port1Only:
|
||||||
{
|
{
|
||||||
g_pad.SetMultitapEnable(0, true);
|
g_pad.GetMultitap(0)->SetEnable(true, 0);
|
||||||
g_pad.SetMultitapEnable(1, false);
|
g_pad.GetMultitap(1)->SetEnable(false, 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MultitapMode::Port2Only:
|
||||||
|
{
|
||||||
|
g_pad.GetMultitap(0)->SetEnable(false, 0);
|
||||||
|
g_pad.GetMultitap(1)->SetEnable(true, 1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MultitapMode::BothPorts:
|
case MultitapMode::BothPorts:
|
||||||
{
|
{
|
||||||
g_pad.SetMultitapEnable(0, true);
|
g_pad.GetMultitap(0)->SetEnable(true, 0);
|
||||||
g_pad.SetMultitapEnable(1, true);
|
g_pad.GetMultitap(1)->SetEnable(true, 4);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -147,6 +147,7 @@ enum class MultitapMode
|
||||||
{
|
{
|
||||||
Disabled,
|
Disabled,
|
||||||
Port1Only,
|
Port1Only,
|
||||||
|
Port2Only,
|
||||||
BothPorts,
|
BothPorts,
|
||||||
Count
|
Count
|
||||||
};
|
};
|
||||||
|
|
|
@ -1573,17 +1573,14 @@ void DrawSettingsWindow()
|
||||||
TinyString section;
|
TinyString section;
|
||||||
TinyString key;
|
TinyString key;
|
||||||
|
|
||||||
|
std::array<TinyString, NUM_CONTROLLER_AND_CARD_PORTS> port_labels = s_settings_copy.GeneratePortLabels();
|
||||||
|
|
||||||
for (u32 port = 0; port < NUM_CONTROLLER_AND_CARD_PORTS; port++)
|
for (u32 port = 0; port < NUM_CONTROLLER_AND_CARD_PORTS; port++)
|
||||||
{
|
{
|
||||||
u32 console_port = port / 4u;
|
if (port_labels[port].IsEmpty())
|
||||||
if (s_settings_copy.IsMultitapEnabledOnPort(console_port))
|
|
||||||
MenuHeading(TinyString::FromFormat("Port %u%c", console_port + 1u, 'A' + (port % 4u)));
|
|
||||||
else if (port < 2u)
|
|
||||||
MenuHeading(TinyString::FromFormat("Port %u", port + 1u));
|
|
||||||
else if (port % 4u == 0u && s_settings_copy.IsMultitapEnabledOnPort(0))
|
|
||||||
MenuHeading(TinyString::FromFormat("Port %u", console_port + 1u));
|
|
||||||
else
|
|
||||||
continue;
|
continue;
|
||||||
|
else
|
||||||
|
MenuHeading(port_labels[port]);
|
||||||
|
|
||||||
settings_changed |= EnumChoiceButton(
|
settings_changed |= EnumChoiceButton(
|
||||||
TinyString::FromFormat(ICON_FA_GAMEPAD " Controller Type##type%u", port),
|
TinyString::FromFormat(ICON_FA_GAMEPAD " Controller Type##type%u", port),
|
||||||
|
|
Loading…
Reference in New Issue