sio.cpp (3723B)
1 // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com> 2 // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) 3 4 #include "sio.h" 5 #include "controller.h" 6 7 #include "util/state_wrapper.h" 8 9 #include "common/bitfield.h" 10 #include "common/bitutils.h" 11 #include "common/log.h" 12 13 #include <array> 14 #include <memory> 15 16 Log_SetChannel(SIO); 17 18 namespace SIO { 19 namespace { 20 21 union SIO_CTRL 22 { 23 u16 bits; 24 25 BitField<u16, bool, 0, 1> TXEN; 26 BitField<u16, bool, 1, 1> DTROUTPUT; 27 BitField<u16, bool, 2, 1> RXEN; 28 BitField<u16, bool, 3, 1> TXOUTPUT; 29 BitField<u16, bool, 4, 1> ACK; 30 BitField<u16, bool, 5, 1> RTSOUTPUT; 31 BitField<u16, bool, 6, 1> RESET; 32 BitField<u16, u8, 8, 2> RXIMODE; 33 BitField<u16, bool, 10, 1> TXINTEN; 34 BitField<u16, bool, 11, 1> RXINTEN; 35 BitField<u16, bool, 12, 1> ACKINTEN; 36 }; 37 38 union SIO_STAT 39 { 40 u32 bits; 41 42 BitField<u32, bool, 0, 1> TXRDY; 43 BitField<u32, bool, 1, 1> RXFIFONEMPTY; 44 BitField<u32, bool, 2, 1> TXDONE; 45 BitField<u32, bool, 3, 1> RXPARITY; 46 BitField<u32, bool, 4, 1> RXFIFOOVERRUN; 47 BitField<u32, bool, 5, 1> RXBADSTOPBIT; 48 BitField<u32, bool, 6, 1> RXINPUTLEVEL; 49 BitField<u32, bool, 7, 1> DSRINPUTLEVEL; 50 BitField<u32, bool, 8, 1> CTSINPUTLEVEL; 51 BitField<u32, bool, 9, 1> INTR; 52 BitField<u32, u32, 11, 15> TMR; 53 }; 54 55 union SIO_MODE 56 { 57 u16 bits; 58 59 BitField<u16, u8, 0, 2> reload_factor; 60 BitField<u16, u8, 2, 2> character_length; 61 BitField<u16, bool, 4, 1> parity_enable; 62 BitField<u16, u8, 5, 1> parity_type; 63 BitField<u16, u8, 6, 2> stop_bit_length; 64 }; 65 } // namespace 66 67 static void SoftReset(); 68 69 static SIO_CTRL s_SIO_CTRL = {}; 70 static SIO_STAT s_SIO_STAT = {}; 71 static SIO_MODE s_SIO_MODE = {}; 72 static u16 s_SIO_BAUD = 0; 73 74 } // namespace SIO 75 76 void SIO::Initialize() 77 { 78 Reset(); 79 } 80 81 void SIO::Shutdown() 82 { 83 } 84 85 void SIO::Reset() 86 { 87 SoftReset(); 88 } 89 90 bool SIO::DoState(StateWrapper& sw) 91 { 92 sw.Do(&s_SIO_CTRL.bits); 93 sw.Do(&s_SIO_STAT.bits); 94 sw.Do(&s_SIO_MODE.bits); 95 sw.Do(&s_SIO_BAUD); 96 97 return !sw.HasError(); 98 } 99 100 u32 SIO::ReadRegister(u32 offset) 101 { 102 switch (offset) 103 { 104 case 0x00: // SIO_DATA 105 { 106 ERROR_LOG("Read SIO_DATA"); 107 108 const u8 value = 0xFF; 109 return (ZeroExtend32(value) | (ZeroExtend32(value) << 8) | (ZeroExtend32(value) << 16) | 110 (ZeroExtend32(value) << 24)); 111 } 112 113 case 0x04: // SIO_STAT 114 { 115 const u32 bits = s_SIO_STAT.bits; 116 return bits; 117 } 118 119 case 0x08: // SIO_MODE 120 return ZeroExtend32(s_SIO_MODE.bits); 121 122 case 0x0A: // SIO_CTRL 123 return ZeroExtend32(s_SIO_CTRL.bits); 124 125 case 0x0E: // SIO_BAUD 126 return ZeroExtend32(s_SIO_BAUD); 127 128 [[unlikely]] default: 129 ERROR_LOG("Unknown register read: 0x{:X}", offset); 130 return UINT32_C(0xFFFFFFFF); 131 } 132 } 133 134 void SIO::WriteRegister(u32 offset, u32 value) 135 { 136 switch (offset) 137 { 138 case 0x00: // SIO_DATA 139 { 140 WARNING_LOG("SIO_DATA (W) <- 0x{:02X}", value); 141 return; 142 } 143 144 case 0x0A: // SIO_CTRL 145 { 146 DEBUG_LOG("SIO_CTRL <- 0x{:04X}", value); 147 148 s_SIO_CTRL.bits = Truncate16(value); 149 if (s_SIO_CTRL.RESET) 150 SoftReset(); 151 152 return; 153 } 154 155 case 0x08: // SIO_MODE 156 { 157 DEBUG_LOG("SIO_MODE <- 0x{:08X}", value); 158 s_SIO_MODE.bits = Truncate16(value); 159 return; 160 } 161 162 case 0x0E: 163 { 164 DEBUG_LOG("SIO_BAUD <- 0x{:08X}", value); 165 s_SIO_BAUD = Truncate16(value); 166 return; 167 } 168 169 default: 170 ERROR_LOG("Unknown register write: 0x{:X} <- 0x{:08X}", offset, value); 171 return; 172 } 173 } 174 175 void SIO::SoftReset() 176 { 177 s_SIO_CTRL.bits = 0; 178 s_SIO_STAT.bits = 0; 179 s_SIO_STAT.DSRINPUTLEVEL = true; 180 s_SIO_STAT.CTSINPUTLEVEL = true; 181 s_SIO_STAT.TXDONE = true; 182 s_SIO_STAT.TXRDY = true; 183 s_SIO_MODE.bits = 0; 184 s_SIO_BAUD = 0xDC; 185 }