6use bincode::{Decode, Encode}; 7use jgenesis_common::num::{GetBit, U16Ext}; 8use std::fmt::Debug; 9 10pub trait EepromState: Copy + Default { 11 #[must_use] 12 fn start(self) -> Self; 13 14 #[must_use] 15 fn stop(self) -> Self; 16 17 #[must_use] 18 fn is_stopped(self) -> bool; 19 20 #[must_use] 21 fn clock(self, data: bool, memory: &mut [u8], dirty: &mut bool) -> Self; 22 23 #[must_use] 24 fn read(self, memory: &[u8]) -> Option<bool>; 25} 26 27#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Encode, Decode)] 28pub struct ShiftRegister { 29 pub received: u8, 30 pub remaining: u8, 31} 32 33impl ShiftRegister { 34 fn new() -> Self { 35 Self { received: 0, remaining: 8 } 36 } 37 38 #[must_use] 39 fn write(self, data: bool) -> Self { 40 Self { received: (self.received << 1) | u8::from(data), remaining: self.remaining - 1 } 41 } 42} 43 44#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Encode, Decode)] 45pub enum X24C01State { 46 Started, 47 #[default] 48 Standby, 49 ReceivingAddress(ShiftRegister), 50 ReceivingData { 51 address: u8, 52 bits: ShiftRegister, 53 }, 54 SendingData { 55 address: u8, 56 bits_remaining: u8, 57 }, 58 PostSend { 59 address: u8, 60 }, 61} 62 63impl EepromState for X24C01State { 64 fn start(self) -> Self { 65 log::trace!("Start"); 66 if self == Self::Standby { Self::Started } else { self } 67 } 68 69 fn stop(self) -> Self { 70 log::trace!("Stop"); 71 Self::Standby 72 } 73 74 fn is_stopped(self) -> bool { 75 self == Self::Standby 76 } 77 78 fn clock(self, data: bool, memory: &mut [u8], dirty: &mut bool) -> Self { 79 match self { 80 Self::Started => Self::ReceivingAddress(ShiftRegister::new()), 81 Self::Standby => Self::Standby, 82 Self::ReceivingAddress(bits) => { 83 if bits.remaining > 0 { 84 Self::ReceivingAddress(bits.write(data)) 85 } else if bits.received.bit(0) { 86 // Read operation 87 let address = bits.received >> 1; 88 Self::SendingData { address, bits_remaining: 7 } 89 } else { 90 // Write operation 91 let address = bits.received >> 1; 92 Self::ReceivingData { address, bits: ShiftRegister::new() } 93 } 94 } 95 Self::ReceivingData { address, bits: ShiftRegister { remaining: 0, .. } } => { 96 // Continue sequential write - but only increment the lowest 2 bits 97 let address = (address & 0xFC) | (address.wrapping_add(1) & 0x03); 98 Self::ReceivingData { address, bits: ShiftRegister::new() } 99 } 100 Self::ReceivingData { address, bits } => { 101 let bits = bits.write(data); 102 if bits.remaining == 0 { 103 log::trace!("Writing {:02X} to {address:02X}", bits.received); 104 memory[address as usize] = bits.received; 105 *dirty = true; 106 } 107 Self::ReceivingData { address, bits } 108 } 109 Self::SendingData { address, bits_remaining: 0 } => { 110 // Acknowledged, continue sequential read 111 let address = (address + 1) & 127; 112 Self::PostSend { address } 113 } 114 Self::SendingData { address, bits_remaining } => { 115 Self::SendingData { address, bits_remaining: bits_remaining - 1 } 116 } 117 Self::PostSend { address } => { 118 if !data { 119 Self::SendingData { address, bits_remaining: 7 } 120 } else { 121 Self::Standby 122 } 123 } 124 } 125 } 126 127 fn read(self, memory: &[u8]) -> Option<bool> { 128 let Self::SendingData { address, bits_remaining } = self else { 129 return None; 130 }; 131 132 if bits_remaining == 8 { 133 return None; 134 } 135 136 Some(memory[address as usize].bit(bits_remaining)) 137 } 138}
Used to emulate the X24C02, X24C08, and X24C16 which all function very similarly
141#[derive(Debug, Clone, Copy, PartialEq, Eq, Encode, Decode)] 142pub enum X24C16State<const ADDRESS_MASK: u16, const PAGE_MASK: u16> { 143 Started { address: u16 }, 144 Standby { address: u16 }, 145 ReceivingDeviceAddress { address: u16, bits: ShiftRegister }, 146 ReceivingWriteAddress { address: u16, bits: ShiftRegister }, 147 ReceivingData { address: u16, bits: ShiftRegister }, 148 SendingData { address: u16, bits_remaining: u8 }, 149 PostSend { address: u16 }, 150}
152impl<const ADDRESS_MASK: u16, const PAGE_MASK: u16> Default 153 for X24C16State<ADDRESS_MASK, PAGE_MASK> 154{ 155 fn default() -> Self { 156 Self::Standby { address: 0 } 157 } 158} 159 160impl<const ADDRESS_MASK: u16, const PAGE_MASK: u16> EepromState 161 for X24C16State<ADDRESS_MASK, PAGE_MASK> 162{ 163 fn start(self) -> Self { 164 log::trace!("transitioning to Start from {self:?}"); 165 match self { 166 Self::Started { address } 167 | Self::Standby { address } 168 | Self::ReceivingDeviceAddress { address, .. } 169 | Self::ReceivingWriteAddress { address, .. } 170 | Self::ReceivingData { address, .. } 171 | Self::SendingData { address, .. } 172 | Self::PostSend { address } => Self::Started { address }, 173 } 174 } 175 176 fn stop(self) -> Self { 177 log::trace!("transitioning to Stop from {self:?}"); 178 match self { 179 Self::Started { address } 180 | Self::Standby { address } 181 | Self::ReceivingDeviceAddress { address, .. } 182 | Self::ReceivingWriteAddress { address, .. } 183 | Self::ReceivingData { address, .. } 184 | Self::SendingData { address, .. } 185 | Self::PostSend { address } => Self::Standby { address }, 186 } 187 } 188 189 fn is_stopped(self) -> bool { 190 matches!(self, Self::Standby { .. }) 191 } 192 193 fn clock(self, data: bool, memory: &mut [u8], dirty: &mut bool) -> Self { 194 match self { 195 Self::Started { address } => { 196 Self::ReceivingDeviceAddress { address, bits: ShiftRegister::new() } 197 } 198 Self::Standby { address } => Self::Standby { address }, 199 Self::ReceivingDeviceAddress { 200 address, 201 bits: ShiftRegister { received, remaining: 0 }, 202 } => { 203 // Bits 3-1 of device address byte are used as bits 10-8 in address 204 let high_bits = u16::from(received & 0x0E) << 7; 205 let address = ((address & 0x00FF) | high_bits) & ADDRESS_MASK; 206 207 if received.bit(0) { 208 // Read operation 209 Self::SendingData { address, bits_remaining: 7 } 210 } else { 211 // Write operation 212 Self::ReceivingWriteAddress { address, bits: ShiftRegister::new() } 213 } 214 } 215 Self::ReceivingDeviceAddress { address, bits } => { 216 Self::ReceivingDeviceAddress { address, bits: bits.write(data) } 217 } 218 Self::ReceivingWriteAddress { 219 address, 220 bits: ShiftRegister { received, remaining: 0 }, 221 } => Self::ReceivingData { 222 address: (address & 0xFF00) | u16::from(received), 223 bits: ShiftRegister::new(), 224 }, 225 Self::ReceivingWriteAddress { address, bits } => { 226 Self::ReceivingWriteAddress { address, bits: bits.write(data) } 227 } 228 Self::ReceivingData { address, bits: ShiftRegister { remaining: 0, .. } } => { 229 // Continue sequential write - but only increment the lowest N bits 230 let address = (address & !PAGE_MASK) | (address.wrapping_add(1) & PAGE_MASK); 231 Self::ReceivingData { address, bits: ShiftRegister::new() } 232 } 233 Self::ReceivingData { address, bits } => { 234 let bits = bits.write(data); 235 if bits.remaining == 0 { 236 memory[address as usize] = bits.received; 237 *dirty = true; 238 } 239 Self::ReceivingData { address, bits } 240 } 241 Self::SendingData { address, bits_remaining: 0 } => { 242 Self::PostSend { address: (address + 1) & ADDRESS_MASK } 243 } 244 Self::SendingData { address, bits_remaining } => { 245 Self::SendingData { address, bits_remaining: bits_remaining - 1 } 246 } 247 Self::PostSend { address } => { 248 if !data { 249 Self::SendingData { address, bits_remaining: 7 } 250 } else { 251 Self::Standby { address } 252 } 253 } 254 } 255 } 256 257 fn read(self, memory: &[u8]) -> Option<bool> { 258 let Self::SendingData { address, bits_remaining } = self else { 259 return None; 260 }; 261 262 if bits_remaining == 8 { 263 return None; 264 } 265 266 Some(memory[address as usize].bit(bits_remaining)) 267 } 268} 269 270#[derive(Debug, Clone, Copy, Encode, Decode)] 271pub enum X24C64State { 272 Started { address: u16 }, 273 Standby { address: u16 }, 274 ReceivingDeviceAddress { address: u16, bits: ShiftRegister }, 275 ReceivingDataAddressFirst { address: u16, bits: ShiftRegister }, 276 ReceivingDataAddressSecond { address: u16, bits: ShiftRegister }, 277 ReceivingData { address: u16, bits: ShiftRegister }, 278 SendingData { address: u16, bits_remaining: u8 }, 279 PostSend { address: u16 }, 280} 281 282impl Default for X24C64State { 283 fn default() -> Self { 284 Self::Standby { address: 0 } 285 } 286} 287 288impl X24C64State { 289 fn address(self) -> u16 { 290 match self { 291 Self::Started { address } 292 | Self::Standby { address } 293 | Self::ReceivingDeviceAddress { address, .. } 294 | Self::ReceivingDataAddressFirst { address, .. } 295 | Self::ReceivingDataAddressSecond { address, .. } 296 | Self::ReceivingData { address, .. } 297 | Self::SendingData { address, .. } 298 | Self::PostSend { address } => address, 299 } 300 } 301} 302 303impl EepromState for X24C64State { 304 fn start(self) -> Self { 305 log::trace!("Start"); 306 Self::Started { address: self.address() } 307 } 308 309 fn stop(self) -> Self { 310 log::trace!("Stop"); 311 Self::Standby { address: self.address() } 312 } 313 314 fn is_stopped(self) -> bool { 315 matches!(self, Self::Standby { .. }) 316 } 317 318 fn clock(self, data: bool, memory: &mut [u8], dirty: &mut bool) -> Self { 319 match self { 320 Self::Started { address } => { 321 Self::ReceivingDeviceAddress { address, bits: ShiftRegister::new() } 322 } 323 Self::Standby { address } => Self::Standby { address }, 324 Self::ReceivingDeviceAddress { 325 address, 326 bits: ShiftRegister { received, remaining: 0 }, 327 } => { 328 let device_address = received >> 1; 329 if device_address != 0b101_0000 { 330 Self::Standby { address } 331 } else if received.bit(0) { 332 Self::SendingData { address, bits_remaining: 7 } 333 } else { 334 Self::ReceivingDataAddressFirst { address, bits: ShiftRegister::new() } 335 } 336 } 337 Self::ReceivingDeviceAddress { address, bits } => { 338 Self::ReceivingDeviceAddress { address, bits: bits.write(data) } 339 } 340 Self::ReceivingDataAddressFirst { 341 address, 342 bits: ShiftRegister { received, remaining: 0 }, 343 } => Self::ReceivingDataAddressSecond { 344 address: u16::from_be_bytes([received & 0x1F, address.lsb()]), 345 bits: ShiftRegister::new(), 346 }, 347 Self::ReceivingDataAddressFirst { address, bits } => { 348 Self::ReceivingDataAddressFirst { address, bits: bits.write(data) } 349 } 350 Self::ReceivingDataAddressSecond { 351 address, 352 bits: ShiftRegister { received, remaining: 0 }, 353 } => Self::ReceivingData { 354 address: u16::from_be_bytes([address.msb(), received]), 355 bits: ShiftRegister::new(), 356 }, 357 Self::ReceivingDataAddressSecond { address, bits } => { 358 Self::ReceivingDataAddressSecond { address, bits: bits.write(data) } 359 } 360 Self::ReceivingData { address, bits: ShiftRegister { received, remaining: 0 } } => { 361 memory[address as usize] = received; 362 *dirty = true; 363 364 Self::ReceivingData { 365 address: ((address + 1) & 0x1F) | (address & !0x1F), 366 bits: ShiftRegister::new(), 367 } 368 } 369 Self::ReceivingData { address, bits } => { 370 Self::ReceivingData { address, bits: bits.write(data) } 371 } 372 Self::SendingData { address, bits_remaining: 0 } => { 373 Self::PostSend { address: (address + 1) & 0x1FFF } 374 } 375 Self::SendingData { address, bits_remaining } => { 376 Self::SendingData { address, bits_remaining: bits_remaining - 1 } 377 } 378 Self::PostSend { address } => { 379 if !data { 380 Self::SendingData { address, bits_remaining: 7 } 381 } else { 382 Self::Standby { address } 383 } 384 } 385 } 386 } 387 388 fn read(self, memory: &[u8]) -> Option<bool> { 389 let Self::SendingData { address, bits_remaining } = self else { return None }; 390 391 let byte = memory[address as usize]; 392 Some(byte.bit(bits_remaining)) 393 } 394} 395 396#[derive(Debug, Clone, Encode, Decode)] 397pub struct EepromChip<State, const N: usize> { 398 memory: [u8; N], 399 dirty: bool, 400 state: State, 401 last_data: bool, 402 last_clock: bool, 403} 404 405impl<State: EepromState + Debug, const N: usize> EepromChip<State, N> { 406 #[must_use] 407 pub fn new(sav_bytes: Option<&Vec<u8>>) -> Self { 408 let mut memory = [0; N]; 409 if let Some(sav_bytes) = sav_bytes 410 && sav_bytes.len() == N 411 { 412 memory.copy_from_slice(sav_bytes); 413 } 414 415 Self { memory, dirty: true, state: State::default(), last_data: false, last_clock: false } 416 } 417 418 pub fn handle_read(&self) -> bool { 419 log::trace!("EEPROM read"); 420 421 if self.state.is_stopped() { 422 return self.last_data; 423 } 424 425 self.state.read(&self.memory).unwrap_or(false) 426 } 427 428 pub fn handle_data_write(&mut self, data: bool) { 429 self.handle_dual_write(data, self.last_clock); 430 } 431 432 pub fn handle_clock_write(&mut self, clock: bool) { 433 self.handle_dual_write(self.last_data, clock); 434 } 435 436 pub fn handle_dual_write(&mut self, data: bool, clock: bool) { 437 log::trace!("EEPROM write sda={} clock={}", u8::from(data), u8::from(clock)); 438 if self.last_clock && clock && data != self.last_data { 439 if data { 440 // Low to high 441 self.state = self.state.stop(); 442 } else { 443 // High to low 444 self.state = self.state.start(); 445 } 446 } else if self.last_clock && !clock { 447 let last_state = self.state; 448 self.state = self.state.clock(self.last_data, &mut self.memory, &mut self.dirty); 449 log::trace!("transitioned from {last_state:?} to {:?}, data is {data}", self.state); 450 } 451 452 self.last_data = data; 453 self.last_clock = clock; 454 } 455 456 pub fn get_and_clear_dirty_bit(&mut self) -> bool { 457 let dirty = self.dirty; 458 self.dirty = false; 459 dirty 460 } 461 462 pub fn get_memory(&self) -> &[u8] { 463 &self.memory 464 } 465} 466 467pub type X24C01Chip = EepromChip<X24C01State, 128>; 468pub type X24C02Chip = EepromChip<X24C16State<0x0FF, 0x03>, 256>; 469pub type X24C08Chip = EepromChip<X24C16State<0x3FF, 0x0F>, 1024>; 470pub type X24C16Chip = EepromChip<X24C16State<0x7FF, 0x0F>, 2048>; 471pub type X24C64Chip = EepromChip<X24C64State, 8192>;