Multitap: Add option to enable only on port 2

This commit is contained in:
Albert Liu 2021-03-01 14:59:59 -08:00
parent 7cb1bd5ac0
commit 3482313e2f
9 changed files with 64 additions and 66 deletions

View file

@ -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);

View file

@ -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;
}; };

View file

@ -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)

View file

@ -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;

View file

@ -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)
{ {

View file

@ -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);

View file

@ -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;
} }

View file

@ -147,6 +147,7 @@ enum class MultitapMode
{ {
Disabled, Disabled,
Port1Only, Port1Only,
Port2Only,
BothPorts, BothPorts,
Count Count
}; };

View file

@ -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),