#pragma once #include "common/bitfield.h" #include "common/fifo_queue.h" #include "types.h" #include #include class StateWrapper; class TimingEvent; class Controller; class MemoryCard; class Pad final { public: Pad(); ~Pad(); void Initialize(); void Shutdown(); void Reset(); bool DoState(StateWrapper& sw); Controller* GetController(u32 slot) const { return m_controllers[slot].get(); } void SetController(u32 slot, std::unique_ptr dev); MemoryCard* GetMemoryCard(u32 slot) { return m_memory_cards[slot].get(); } void SetMemoryCard(u32 slot, std::unique_ptr dev); u32 ReadRegister(u32 offset); void WriteRegister(u32 offset, u32 value); private: static constexpr u32 NUM_SLOTS = 2; enum class State : u32 { Idle, Transmitting, WaitingForACK }; enum class ActiveDevice : u8 { None, Controller, MemoryCard }; union JOY_CTRL { u16 bits; BitField TXEN; BitField SELECT; BitField RXEN; BitField ACK; BitField RESET; BitField RXIMODE; BitField TXINTEN; BitField RXINTEN; BitField ACKINTEN; BitField SLOT; }; union JOY_STAT { u32 bits; BitField TXRDY; BitField RXFIFONEMPTY; BitField TXDONE; BitField ACKINPUT; BitField INTR; BitField TMR; }; union JOY_MODE { u16 bits; BitField reload_factor; BitField character_length; BitField parity_enable; BitField parity_type; BitField clk_polarity; }; bool IsTransmitting() const { return m_state != State::Idle; } bool CanTransfer() const { return m_transmit_buffer_full && m_JOY_CTRL.SELECT && m_JOY_CTRL.TXEN; } TickCount GetTransferTicks() const { return static_cast(ZeroExtend32(m_JOY_BAUD) * 8); } // From @JaCzekanski // ACK lasts ~96 ticks or approximately 2.84us at master clock (not implemented). // ACK delay is between 6.8us-13.7us, or ~338 ticks at master clock for approximately 9.98us. // Memory card responds faster, approximately 5us or ~170 ticks. static constexpr TickCount GetACKTicks(bool memory_card) { return memory_card ? 170 : 450; } void SoftReset(); void UpdateJoyStat(); void TransferEvent(TickCount ticks_late); void BeginTransfer(); void DoTransfer(TickCount ticks_late); void DoACK(); void EndTransfer(); void ResetDeviceTransferState(); std::array, NUM_SLOTS> m_controllers; std::array, NUM_SLOTS> m_memory_cards; std::unique_ptr m_transfer_event; State m_state = State::Idle; JOY_CTRL m_JOY_CTRL = {}; JOY_STAT m_JOY_STAT = {}; JOY_MODE m_JOY_MODE = {}; u16 m_JOY_BAUD = 0; ActiveDevice m_active_device = ActiveDevice::None; u8 m_receive_buffer = 0; u8 m_transmit_buffer = 0; u8 m_transmit_value = 0; bool m_receive_buffer_full = false; bool m_transmit_buffer_full = false; }; extern Pad g_pad;