1//! EEPROM save memory code 2//! 3//! Comes in 512-byte and 8KB variants; protocol is the same except for the number of address bits 4 5use bincode::{Decode, Encode}; 6use jgenesis_common::num::GetBit; 7 8#[derive(Debug, Clone, Copy, PartialEq, Eq, Encode, Decode)] 9enum Request { 10 Read, 11 Write, 12} 13 14#[derive(Debug, Clone, Copy, Encode, Decode)] 15enum EepromState { 16 Idle, 17 ReceivingRequestType, 18 ReceivingAddress { address: u16, remaining: u8, request: Request }, 19 ReceivingData { bits: u64, remaining: u8, address: u16 }, 20 PreparingSend { bits: u64, wait_remaining: u8 }, 21 SendingData { bits: u64, remaining: u8 }, 22 AwaitingEndMarker { request: Request, address: u16 }, 23} 24 25#[derive(Debug, Clone, Encode, Decode)] 26pub struct Eeprom<const LEN: usize, const ADDRESS_BITS: u8> { 27 memory: Box<[u8]>, 28 state: EepromState, 29} 30 31pub type Eeprom512 = Eeprom<512, 6>; 32pub type Eeprom8K = Eeprom<8192, 14>; 33 34impl<const LEN: usize, const ADDRESS_BITS: u8> Eeprom<LEN, ADDRESS_BITS> { 35 pub fn new(initial_save: Option<&Vec<u8>>) -> Self { 36 let mut memory = vec![0xFF; LEN].into_boxed_slice(); 37 38 if let Some(initial_save) = initial_save 39 && initial_save.len() >= LEN 40 { 41 memory.copy_from_slice(&initial_save[..LEN]); 42 } 43 44 Self { memory, state: EepromState::Idle } 45 } 46 47 pub fn read(&mut self) -> bool { 48 log::trace!("EEPROM read, current state {:X?}", self.state); 49 50 match self.state { 51 EepromState::PreparingSend { bits, mut wait_remaining } => { 52 wait_remaining -= 1; 53 self.state = if wait_remaining == 0 { 54 EepromState::SendingData { bits, remaining: 64 } 55 } else { 56 EepromState::PreparingSend { bits, wait_remaining } 57 }; 58 true 59 } 60 EepromState::SendingData { mut bits, mut remaining } => { 61 let bit = bits.bit(63); 62 bits <<= 1; 63 remaining -= 1; 64 65 self.state = if remaining == 0 { 66 EepromState::Idle 67 } else { 68 EepromState::SendingData { bits, remaining } 69 }; 70 71 bit 72 } 73 _ => true, 74 } 75 } 76 77 pub fn write(&mut self, bit: bool) { 78 log::trace!("EEPROM write {}, current state {:X?}", u8::from(bit), self.state); 79 80 self.state = match self.state { 81 EepromState::Idle => { 82 if bit { 83 EepromState::ReceivingRequestType 84 } else { 85 EepromState::Idle 86 } 87 } 88 EepromState::ReceivingRequestType => EepromState::ReceivingAddress { 89 address: 0, 90 remaining: ADDRESS_BITS, 91 request: if bit { Request::Read } else { Request::Write }, 92 }, 93 EepromState::ReceivingAddress { mut address, mut remaining, request } => { 94 address = (address << 1) | u16::from(bit); 95 remaining -= 1; 96 97 if remaining == 0 { 98 match request { 99 Request::Read => EepromState::AwaitingEndMarker { request, address }, 100 Request::Write => { 101 EepromState::ReceivingData { bits: 0, remaining: 64, address } 102 } 103 } 104 } else { 105 EepromState::ReceivingAddress { address, remaining, request } 106 } 107 } 108 EepromState::ReceivingData { mut bits, mut remaining, address } => { 109 bits = (bits << 1) | u64::from(bit); 110 remaining -= 1; 111 112 if remaining == 0 { 113 let byte_addr = ((address << 3) as usize) & (LEN - 1); 114 self.memory[byte_addr..byte_addr + 8].copy_from_slice(&bits.to_be_bytes()); 115 EepromState::AwaitingEndMarker { request: Request::Write, address } 116 } else { 117 EepromState::ReceivingData { bits, remaining, address } 118 } 119 } 120 EepromState::PreparingSend { bits, wait_remaining } => { 121 EepromState::PreparingSend { bits, wait_remaining } 122 } 123 EepromState::SendingData { bits, remaining } => { 124 EepromState::SendingData { bits, remaining } 125 } 126 EepromState::AwaitingEndMarker { request, address } => match request { 127 Request::Read => { 128 let byte_addr = ((address << 3) as usize) & (LEN - 1); 129 let bits = u64::from_be_bytes( 130 self.memory[byte_addr..byte_addr + 8].try_into().unwrap(), 131 ); 132 EepromState::PreparingSend { bits, wait_remaining: 4 } 133 } 134 Request::Write => EepromState::Idle, 135 }, 136 }; 137 138 log::trace!(" New state {:X?}", self.state); 139 } 140 141 pub fn memory(&self) -> &[u8] { 142 &self.memory 143 } 144} 145 146#[cfg(test)] 147mod tests { 148 use super::*; 149 150 fn eeprom_write<const LEN: usize, const ADDRESS_BITS: u8>( 151 eeprom: &mut Eeprom<LEN, ADDRESS_BITS>, 152 address: u16, 153 value: u64, 154 ) { 155 // Write: 10, then address (MSB first), then data, then 0 156 eeprom.write(true); 157 eeprom.write(false); 158 159 let mut address_shift = address; 160 for _ in 0..ADDRESS_BITS { 161 eeprom.write(address_shift.bit(ADDRESS_BITS - 1)); 162 address_shift <<= 1; 163 } 164 165 let mut value_shift = value; 166 for _ in 0..64 { 167 eeprom.write(value_shift.bit(63)); 168 value_shift <<= 1; 169 } 170 171 eeprom.write(false); 172 } 173 174 fn eeprom_read<const LEN: usize, const ADDRESS_BITS: u8>( 175 eeprom: &mut Eeprom<LEN, ADDRESS_BITS>, 176 address: u16, 177 ) -> u64 { 178 // Read: 10, then address (MSB first), then 0, then read data (ignore first 4 bits) 179 eeprom.write(true); 180 eeprom.write(true); 181 182 let mut address_shift = address; 183 for _ in 0..ADDRESS_BITS { 184 eeprom.write(address_shift.bit(ADDRESS_BITS - 1)); 185 address_shift <<= 1; 186 } 187 188 eeprom.write(false); 189 190 // Skip first 4 bits 191 for _ in 0..4 { 192 eeprom.read(); 193 } 194 195 let mut value: u64 = 0; 196 for _ in 0..64 { 197 value = (value << 1) | u64::from(eeprom.read()); 198 } 199 200 value 201 } 202 203 fn write_then_read<const LEN: usize, const ADDRESS_BITS: u8>( 204 mut eeprom: Eeprom<LEN, ADDRESS_BITS>, 205 ) { 206 for _ in 0..100 { 207 eeprom.memory.fill(0); 208 209 let address: u16 = rand::random(); 210 211 let mut value: u64 = 0; 212 while value == 0 { 213 value = rand::random(); 214 } 215 216 eeprom_write(&mut eeprom, address, value); 217 assert_eq!(value, eeprom_read(&mut eeprom, address)); 218 assert_eq!(0, eeprom_read(&mut eeprom, address.wrapping_add(1))); 219 assert_eq!(0, eeprom_read(&mut eeprom, address.wrapping_sub(1))); 220 } 221 } 222 223 #[test] 224 fn write_then_read_512() { 225 write_then_read(Eeprom512::new(None)); 226 } 227 228 #[test] 229 fn write_then_read_8k() { 230 write_then_read(Eeprom8K::new(None)); 231 232 // Test that highest 4 address bits are ignored 233 let mut eeprom = Eeprom8K::new(None); 234 eeprom.memory.fill(0); 235 236 let value = 0x0123456789ABCDEF; 237 eeprom_write(&mut eeprom, 0x001F, value); 238 assert_eq!(value, eeprom_read(&mut eeprom, 0x001F)); 239 assert_eq!(value, eeprom_read(&mut eeprom, 0xFC1F)); 240 assert_eq!(0, eeprom_read(&mut eeprom, 0xFE1F)); 241 } 242}