tgbr_core/
serial.rs

1use bitvec::prelude::*;
2use log::trace;
3use serde::{Deserialize, Serialize};
4
5use crate::{
6    consts::INT_SERIAL,
7    context,
8    interface::LinkCable,
9    util::{pack, trait_alias},
10};
11
12#[derive(Default, Serialize, Deserialize)]
13pub struct SerialTransfer {
14    buf: u8,
15    recv_buf: Option<u8>,
16    transfer_progress: bool,
17    use_internal_clock: bool,
18    transfer_timer: u64,
19    transfer_pos: usize,
20    #[serde(skip)]
21    link_cable: Option<Box<dyn LinkCable + Send + Sync>>,
22}
23
24trait_alias!(pub trait Context = context::InterruptFlag);
25
26impl SerialTransfer {
27    pub fn set_link_cable(&mut self, link_cable: Option<Box<dyn LinkCable + Send + Sync>>) {
28        self.link_cable = link_cable;
29    }
30
31    pub fn tick(&mut self, ctx: &mut impl Context) {
32        if !self.transfer_progress {
33            return;
34        }
35
36        // Check incomming data
37        if self.recv_buf.is_none() {
38            if let Some(r) = &mut self.link_cable {
39                self.recv_buf = r.try_recv();
40            }
41        }
42
43        let mut done = false;
44
45        if self.use_internal_clock {
46            // Transfer one bit per 128 tick (8192 Hz)
47            self.transfer_timer += 1;
48            if self.transfer_timer == 128 {
49                self.transfer_timer = 0;
50                self.transfer_pos += 1;
51
52                if self.transfer_pos == 8 {
53                    done = true;
54                }
55            }
56        } else {
57            // FIXME: wait when recieve data too fast
58            if self.recv_buf.is_some() {
59                done = true;
60            }
61        }
62
63        if done {
64            self.buf = self.recv_buf.unwrap_or(!0);
65            self.recv_buf = None;
66            self.transfer_pos = 0;
67            self.transfer_progress = false;
68            ctx.set_interrupt_flag_bit(INT_SERIAL);
69        }
70    }
71
72    pub fn read_sb(&mut self) -> u8 {
73        trace!("Read SB = ${:02X}", self.buf);
74        self.buf
75    }
76
77    pub fn write_sb(&mut self, data: u8) {
78        trace!("Write SB = ${data:02x}");
79        self.buf = data;
80    }
81
82    pub fn read_sc(&mut self) -> u8 {
83        let data = pack! {
84            7     => self.transfer_progress,
85            1..=6 => !0,
86            0     => self.use_internal_clock,
87        };
88        trace!("Read SB = ${data:02X}");
89        data
90    }
91
92    pub fn write_sc(&mut self, data: u8) {
93        trace!("Write SC = ${data:02x}");
94        let v = data.view_bits::<Lsb0>();
95        self.use_internal_clock = v[0];
96        if v[7] {
97            if let Some(link_cable) = &mut self.link_cable {
98                link_cable.send(self.buf);
99            }
100            self.transfer_progress = true;
101            self.transfer_timer = 0;
102            self.transfer_pos = 0;
103            self.recv_buf = None;
104        } else {
105            self.transfer_progress = false;
106        }
107    }
108}