// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #include "sio.h" #include "controller.h" #include "interrupt_controller.h" #include "memory_card.h" #include "util/state_wrapper.h" #include "common/bitfield.h" #include "common/bitutils.h" #include "common/fifo_queue.h" #include "common/log.h" #include #include Log_SetChannel(SIO); namespace SIO { namespace { union SIO_CTRL { u16 bits; BitField TXEN; BitField DTROUTPUT; BitField RXEN; BitField TXOUTPUT; BitField ACK; BitField RTSOUTPUT; BitField RESET; BitField RXIMODE; BitField TXINTEN; BitField RXINTEN; BitField ACKINTEN; }; union SIO_STAT { u32 bits; BitField TXRDY; BitField RXFIFONEMPTY; BitField TXDONE; BitField RXPARITY; BitField RXFIFOOVERRUN; BitField RXBADSTOPBIT; BitField RXINPUTLEVEL; BitField DSRINPUTLEVEL; BitField CTSINPUTLEVEL; BitField INTR; BitField TMR; }; union SIO_MODE { u16 bits; BitField reload_factor; BitField character_length; BitField parity_enable; BitField parity_type; BitField stop_bit_length; }; } // namespace static void SoftReset(); static SIO_CTRL s_SIO_CTRL = {}; static SIO_STAT s_SIO_STAT = {}; static SIO_MODE s_SIO_MODE = {}; static u16 s_SIO_BAUD = 0; } // namespace SIO void SIO::Initialize() { Reset(); } void SIO::Shutdown() { } void SIO::Reset() { SoftReset(); } bool SIO::DoState(StateWrapper& sw) { sw.Do(&s_SIO_CTRL.bits); sw.Do(&s_SIO_STAT.bits); sw.Do(&s_SIO_MODE.bits); sw.Do(&s_SIO_BAUD); return !sw.HasError(); } u32 SIO::ReadRegister(u32 offset) { switch (offset) { case 0x00: // SIO_DATA { Log_ErrorPrintf("Read SIO_DATA"); const u8 value = 0xFF; return (ZeroExtend32(value) | (ZeroExtend32(value) << 8) | (ZeroExtend32(value) << 16) | (ZeroExtend32(value) << 24)); } case 0x04: // SIO_STAT { const u32 bits = s_SIO_STAT.bits; return bits; } case 0x08: // SIO_MODE return ZeroExtend32(s_SIO_MODE.bits); case 0x0A: // SIO_CTRL return ZeroExtend32(s_SIO_CTRL.bits); case 0x0E: // SIO_BAUD return ZeroExtend32(s_SIO_BAUD); default: Log_ErrorPrintf("Unknown register read: 0x%X", offset); return UINT32_C(0xFFFFFFFF); } } void SIO::WriteRegister(u32 offset, u32 value) { switch (offset) { case 0x00: // SIO_DATA { Log_WarningPrintf("SIO_DATA (W) <- 0x%02X", value); return; } case 0x0A: // SIO_CTRL { Log_DebugPrintf("SIO_CTRL <- 0x%04X", value); s_SIO_CTRL.bits = Truncate16(value); if (s_SIO_CTRL.RESET) SoftReset(); return; } case 0x08: // SIO_MODE { Log_DebugPrintf("SIO_MODE <- 0x%08X", value); s_SIO_MODE.bits = Truncate16(value); return; } case 0x0E: { Log_DebugPrintf("SIO_BAUD <- 0x%08X", value); s_SIO_BAUD = Truncate16(value); return; } default: Log_ErrorPrintf("Unknown register write: 0x%X <- 0x%08X", offset, value); return; } } void SIO::SoftReset() { s_SIO_CTRL.bits = 0; s_SIO_STAT.bits = 0; s_SIO_STAT.DSRINPUTLEVEL = true; s_SIO_STAT.CTSINPUTLEVEL = true; s_SIO_STAT.TXDONE = true; s_SIO_STAT.TXRDY = true; s_SIO_MODE.bits = 0; s_SIO_BAUD = 0xDC; }