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}