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 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 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 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}