SH7604 serial communication interface (SCI)
No 32X games use this but some test cartridges do
9#[derive(Debug, Clone, Encode, Decode)] 10pub struct SerialInterface { 11 name: String, 12 tx_enabled: bool, 13 rx_enabled: bool, 14 tx_interrupt_enabled: bool, 15 rx_interrupt_enabled: bool, 16 transfer_data: u8, 17 transfer_shift: u8, 18 transfer_clocks: u64, 19 receive_data: u8, 20 tx_data_empty: bool, 21 rx_data_full: bool, 22 transfer_end: bool, 23 clock_select: u8, 24 bit_rate: u8, 25} 26 27impl SerialInterface { 28 pub fn new(name: String) -> Self { 29 Self { 30 name, 31 tx_enabled: false, 32 rx_enabled: false, 33 tx_interrupt_enabled: false, 34 rx_interrupt_enabled: false, 35 transfer_data: 0xFF, 36 transfer_shift: 0xFF, 37 transfer_clocks: 0, 38 receive_data: 0x00, 39 tx_data_empty: true, 40 rx_data_full: false, 41 transfer_end: true, 42 clock_select: 0, 43 bit_rate: 0, 44 } 45 } 46 47 pub fn process<B: BusInterface>(&mut self, sh2_clocks_elapsed: u64, bus: &mut B) { 48 if self.rx_enabled 49 && !self.rx_data_full 50 && let Some(rx) = bus.serial_rx() 51 { 52 self.receive_data = rx; 53 self.rx_data_full = true; 54 } 55 56 if self.transfer_clocks == 0 { 57 if self.tx_enabled && !self.tx_data_empty { 58 // TODO TX interrupt 59 self.transfer_shift = self.transfer_data; 60 self.transfer_clocks = estimate_tx_clocks(self.clock_select, self.bit_rate); 61 self.tx_data_empty = true; 62 log::debug!("TX clocks: {}", self.transfer_clocks); 63 } else { 64 return; 65 } 66 } 67 68 self.transfer_clocks = self.transfer_clocks.saturating_sub(sh2_clocks_elapsed); 69 if self.transfer_clocks == 0 { 70 bus.serial_tx(self.transfer_shift); 71 if !self.tx_data_empty { 72 // TODO TX interrupt 73 self.transfer_shift = self.transfer_data; 74 self.transfer_clocks = estimate_tx_clocks(self.clock_select, self.bit_rate); 75 self.tx_data_empty = true; 76 log::debug!("TX clocks: {}", self.transfer_clocks); 77 } else { 78 // TODO transfer end interrupt 79 self.transfer_end = true; 80 } 81 } 82 } 83 84 pub fn read_register(&self, address: u32) -> u8 { 85 log::debug!("[{}] SCI read {address:08X}", self.name); 86 87 match address { 88 0xFFFFFE00 => self.read_mode(), 89 0xFFFFFE01 => self.bit_rate, 90 0xFFFFFE02 => self.read_control(), 91 0xFFFFFE03 => self.transfer_data, 92 0xFFFFFE04 => self.read_status(), 93 0xFFFFFE05 => self.read_rx(), 94 _ => panic!("Invalid SCI register address: {address:08X}"), 95 } 96 } 97 98 pub fn write_register(&mut self, address: u32, value: u8) { 99 match address { 100 0xFFFFFE00 => self.write_mode(value), 101 0xFFFFFE01 => self.write_bit_rate(value), 102 0xFFFFFE02 => self.write_control(value), 103 0xFFFFFE03 => self.write_tx(value), 104 0xFFFFFE04 => self.write_status(value), 105 // RX data register, ignore writes 106 0xFFFFFE05 => {} 107 _ => panic!("Invalid SCI register address: {address:08X} {value:02X}"), 108 } 109 } 110 111 // $FFFFFE00: SMR (Serial mode) 112 fn read_mode(&self) -> u8 { 113 self.clock_select 114 } 115 116 // $FFFFFE00: SMR (Serial mode) 117 fn write_mode(&mut self, value: u8) { 118 self.clock_select = value & 3; 119 120 log::debug!("[{}] SMR write: {value:02X}", self.name); 121 log::debug!(" Clocked synchronous mode: {}", value.bit(7)); 122 log::debug!(" Character length: {}", if value.bit(6) { "7-bit" } else { "8-bit" }); 123 log::debug!(" Parity check enabled: {}", value.bit(5)); 124 log::debug!(" Parity mode odd/even flag: {}", value.bit(4)); 125 log::debug!(" Stop bit length bit: {}", value.bit(3)); 126 log::debug!(" Multiprocessor mode: {}", value.bit(2)); 127 log::debug!( 128 " Clock select: {}", 129 match value & 3 { 130 0 => "sysclk/4", 131 1 => "sysclk/16", 132 2 => "sysclk/64", 133 3 => "sysclk/256", 134 _ => unreachable!(), 135 } 136 ); 137 } 138 139 // $FFFFFE01: BRR (Bit rate) 140 fn write_bit_rate(&mut self, value: u8) { 141 self.bit_rate = value; 142 log::debug!("[{}] BRR write: {value:02X}", self.name); 143 } 144 145 // $FFFFFE02: SCR (Serial control) 146 fn read_control(&self) -> u8 { 147 (u8::from(self.tx_interrupt_enabled) << 7) 148 | (u8::from(self.rx_interrupt_enabled) << 6) 149 | (u8::from(self.tx_enabled) << 5) 150 | (u8::from(self.rx_enabled) << 4) 151 } 152 153 // $FFFFFE02: SCR (Serial control) 154 fn write_control(&mut self, value: u8) { 155 self.tx_interrupt_enabled = value.bit(7); 156 self.rx_interrupt_enabled = value.bit(6); 157 self.tx_enabled = value.bit(5); 158 self.rx_enabled = value.bit(4); 159 160 log::debug!("[{}] SCR write: {value:02X}", self.name); 161 log::debug!(" TX interrupt enabled: {}", self.tx_interrupt_enabled); 162 log::debug!(" RX interrupt enabled: {}", self.rx_interrupt_enabled); 163 log::debug!(" TX enabled: {}", self.tx_enabled); 164 log::debug!(" RX enabled: {}", self.rx_enabled); 165 log::debug!(" Multiprocessor interrupt enabled: {}", value.bit(3)); 166 log::debug!(" Transfer end interrupt enabled: {}", value.bit(2)); 167 log::debug!(" Clock enabled bits: {}", value & 3); 168 } 169 170 // $FFFFFE03: TDR (Transfer data register) 171 fn write_tx(&mut self, value: u8) { 172 self.transfer_data = value; 173 174 log::trace!("[{}] TDR write: {value:02X}", self.name); 175 } 176 177 // $FFFFFE04: SSR (Serial status) 178 fn read_status(&self) -> u8 { 179 (u8::from(self.tx_data_empty) << 7) 180 | (u8::from(self.rx_data_full) << 6) 181 | (u8::from(self.transfer_end) << 2) 182 } 183 184 // $FFFFFE04: SSR (Serial status) 185 fn write_status(&mut self, value: u8) { 186 self.tx_data_empty &= value.bit(7); 187 self.transfer_end &= value.bit(7); 188 self.rx_data_full &= value.bit(6); 189 190 log::debug!("[{}] SSR write: {value:02X}", self.name); 191 log::debug!(" Clear TX data empty: {}", !value.bit(7)); 192 log::debug!(" Clear RX data full: {}", !value.bit(6)); 193 log::debug!(" Multiprocessor bit: {}", value & 1); 194 } 195 196 // $FFFFFE05: RDR (Receive data register) 197 fn read_rx(&self) -> u8 { 198 self.receive_data 199 } 200 201 pub fn rx_interrupt_pending(&self) -> bool { 202 self.rx_interrupt_enabled && self.rx_data_full 203 } 204} 205 206fn estimate_tx_clocks(clock_select: u8, bit_rate: u8) -> u64 { 207 let clocks_per_bit = if clock_select == 0 { 208 128 * (u64::from(bit_rate) + 1) 209 } else { 210 256 * (1 << (2 * clock_select - 1)) * (u64::from(bit_rate) + 1) 211 }; 212 213 8 * clocks_per_bit 214}