Skip to main content

gb/
serial.rs

1//! Byte exchange over the link cable.
2//!
3//! A transfer is always an exchange. Eight bits leave as eight arrive, and one
4//! cannot be had without the other. One of the two Game Boys supplies the clock
5//! and so decides when it happens: [`drive`] is that side, [`follow`] the other.
6//!
7//! ```ignore
8//! let answer = serial::exchange(b'?', Rate::Slow);
9//! ```
10//!
11//! # Waiting
12//!
13//! Nothing here gives up on its own. A [`follow`] with nothing at the far end
14//! waits for a clock that never comes. Count the frames and
15//! [`abort`](Transfer::abort) it. [`drive`] always finishes, reading `$FF`
16//! off a cable with nothing on it.
17//!
18//! A Game Boy about to be clocked has to be waiting before the other one
19//! starts, so the clocking side has to pause between bytes. How long depends on
20//! what the far end does with them.
21//!
22//! See <https://gbdev.io/pandocs/Serial_Data_Transfer_(Link_Cable).html>.
23
24use crate::mmio::{SB, SC, SerialCtrl};
25
26/// How fast this Game Boy clocks the wire.
27#[derive(Clone, Copy, Debug, PartialEq, Eq)]
28pub enum Rate {
29    /// 8192 bits a second, the rate every Game Boy handles.
30    Slow,
31    /// 262144 bits a second, which only a Game Boy Color can clock. The far
32    /// end follows whatever reaches it and need not be one.
33    #[cfg(feature = "cgb")]
34    #[cfg_attr(docsrs, doc(cfg(feature = "cgb")))]
35    Fast,
36}
37
38impl Rate {
39    const fn fast(self) -> bool {
40        match self {
41            Rate::Slow => false,
42            #[cfg(feature = "cgb")]
43            Rate::Fast => true,
44        }
45    }
46}
47
48/// A byte on its way out with another on its way in.
49///
50/// Dropping this leaves the wire as it was. The transfer runs to its end, or
51/// goes on waiting, with nobody to collect what arrives.
52pub struct Transfer(());
53
54impl Transfer {
55    /// The byte that arrived, once the transfer has finished.
56    #[inline]
57    pub fn poll(&self) -> Option<u8> {
58        (!SC.read().transfer_enable()).then(|| SB.read())
59    }
60
61    /// Give up.
62    ///
63    /// A transfer that has already finished is left alone, so what arrived is
64    /// still there to [`poll`](Self::poll).
65    #[inline]
66    pub fn abort(self) {
67        let ctrl = SC.read();
68        if ctrl.transfer_enable() {
69            SC.write(ctrl.with_transfer_enable(false));
70        }
71    }
72}
73
74/// Clock the wire and wait for the byte coming the other way.
75///
76/// About 1024 M-cycles at [`Rate::Slow`], a seventeenth of a frame, and 32 at
77/// [`Rate::Fast`]. Double speed leaves both figures alone, the wire and the
78/// processor keeping step.
79#[inline]
80pub fn exchange(byte: u8, rate: Rate) -> u8 {
81    let transfer = drive(byte, rate);
82    loop {
83        if let Some(answer) = transfer.poll() {
84            return answer;
85        }
86    }
87}
88
89/// Clock the wire and carry on.
90#[inline]
91pub fn drive(byte: u8, rate: Rate) -> Transfer {
92    SB.write(byte);
93    SC.write(
94        SerialCtrl::new()
95            .with_clock_select(true)
96            .with_clock_speed(rate.fast())
97            .with_transfer_enable(true),
98    );
99    Transfer(())
100}
101
102/// Hold a byte out for the other Game Boy to clock when it is ready.
103#[inline]
104pub fn follow(byte: u8) -> Transfer {
105    SB.write(byte);
106    SC.write(SerialCtrl::new().with_transfer_enable(true));
107    Transfer(())
108}