eeprom.rsannotatedeeprom.rssource471 lines · 15.9 KB · raw

Implementations for the 24C01, 24C02, 24C08, and 24C16 EEPROM chips

3#[cfg(test)]
4mod tests;
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>;