1use crate::memory::{InterruptManager, InterruptType};
2use crate::GameBoyConfig;
3use bitflags::bitflags;
4use save_state::Savable;
5
6pub trait SerialDevice {
12 fn exchange_bit_external_clock(&mut self, bit: bool) -> bool;
15}
16
17bitflags! {
18 #[derive(Savable)]
19 #[savable(bitflags)]
20 struct SerialControl: u8 {
21 const IN_TRANSFER = 1 << 7;
22 const CLOCK_SPEED = 1 << 1;
23 const CLOCK_SOURCE = 1 << 0;
24 }
25}
26
27impl SerialControl {
28 fn is_internal_clock(&self) -> bool {
29 self.contains(Self::CLOCK_SOURCE)
30 }
31
32 fn in_transfer(&self) -> bool {
33 self.contains(Self::IN_TRANSFER)
34 }
35
36 fn end_transfere(&mut self) {
37 self.set(Self::IN_TRANSFER, false);
38 }
39
40 fn clock_bit(&self) -> u8 {
43 if self.contains(Self::CLOCK_SPEED) {
44 1
46 } else {
47 6
49 }
50 }
51}
52
53#[derive(Savable)]
54pub struct Serial {
55 serial_control: SerialControl,
56 transfere_data: u8,
57 bits_remaining: u8,
58 pub internal_timer: u8,
59 config: GameBoyConfig,
60}
61
62impl Serial {
63 pub fn new(config: GameBoyConfig) -> Self {
64 Self {
65 serial_control: SerialControl::from_bits_truncate(0),
66 transfere_data: 0,
67 bits_remaining: 0,
68 internal_timer: 2,
69 config,
70 }
71 }
72
73 pub fn new_skip_boot_rom(config: GameBoyConfig) -> Self {
74 Self {
75 internal_timer: if config.is_dmg { 0xF3 } else { 0 },
79 ..Self::new(config)
80 }
81 }
82
83 pub fn read_data(&self) -> u8 {
84 self.transfere_data
85 }
86
87 pub fn write_data(&mut self, data: u8) {
88 self.transfere_data = data
89 }
90
91 pub fn read_control(&self) -> u8 {
92 0x7E | self.serial_control.bits()
93 }
94
95 pub fn write_control(&mut self, mut data: u8) {
96 if self.config.is_dmg {
97 data &= 0x81;
99 }
100
101 self.serial_control = SerialControl::from_bits_truncate(data);
102 if self.serial_control.in_transfer() {
104 self.bits_remaining = 8;
105 }
106 }
107
108 pub fn clock_for_bit<I: InterruptManager>(&mut self, interrupt: &mut I) -> Option<bool> {
112 let old_bit = (self.internal_timer >> self.serial_control.clock_bit()) & 1 == 1;
113 self.internal_timer = self.internal_timer.wrapping_add(1);
114 let new_bit = (self.internal_timer >> self.serial_control.clock_bit()) & 1 == 1;
115 let can_clock = old_bit && !new_bit;
116
117 if can_clock && self.bits_remaining > 0 && self.serial_control.is_internal_clock() {
118 let out = self.transfere_data & 0x80 != 0;
119 self.transfere_data = self.transfere_data.wrapping_shl(1);
120
121 self.transfere_data |= 1;
124
125 self.bits_remaining -= 1;
126
127 if self.bits_remaining == 0 {
128 self.serial_control.end_transfere();
129 interrupt.request_interrupt(InterruptType::Serial);
130 }
131
132 Some(out)
133 } else {
134 None
139 }
140 }
141
142 pub fn receive_bit(&mut self, bit: bool) {
143 assert!(self.serial_control.is_internal_clock());
145
146 self.transfere_data &= !1;
148 self.transfere_data |= bit as u8;
149 }
150}