Skip to main content

padme_core/
serial.rs

1use log::trace;
2
3use crate::interrupt::{InterruptHandler, InterruptFlag};
4use crate::region::*;
5
6// Default registers
7const DEFAULT_REG_SB: u8        = 0x00;
8const DEFAULT_REG_SC: u8        = 0x7E;
9
10const FLAG_SC_TRANSFER: u8      = 0x80;
11const FLAG_SC_INT_CLOCK: u8     = 0x01;
12
13pub trait SerialOutput {
14    fn putchar(&mut self, c: u8);
15}
16
17pub struct Serial {
18    /// Serial transfer data (R/W)
19    reg_sb: u8,
20    /// Serial transfer control (R/W)
21    reg_sc: u8,
22}
23
24impl Serial {
25    pub fn new() -> Self {
26        Self {
27            reg_sb: DEFAULT_REG_SB,
28            reg_sc: DEFAULT_REG_SC,
29        }
30    }
31
32    /// Reset all registers and states
33    pub fn reset(&mut self) {
34        self.reg_sb = DEFAULT_REG_SB;
35        self.reg_sc = DEFAULT_REG_SC;
36    }
37
38    pub fn step<SO>(&mut self, out: &mut SO, it: &mut InterruptHandler)
39        where SO: SerialOutput
40    {
41        const NEW_CHAR_FLAG: u8 = FLAG_SC_TRANSFER | FLAG_SC_INT_CLOCK;
42
43        if (self.reg_sc & NEW_CHAR_FLAG) == NEW_CHAR_FLAG {
44            self.reg_sc &= !FLAG_SC_TRANSFER;
45            trace!("write character: 0x{:02X} ({})", self.reg_sb, self.reg_sb as char);
46            out.putchar(self.reg_sb);
47            it.request(InterruptFlag::Serial);
48        }
49    }
50}
51
52impl MemoryRegion for Serial {
53    fn read(&self, address: u16) -> u8 {
54        match address {
55            REG_SB_ADDR => self.reg_sb,
56            REG_SC_ADDR => self.reg_sc,
57            _ => unreachable!(),
58        }
59    }
60
61    fn write(&mut self, address: u16, value: u8) {
62        match address {
63            REG_SB_ADDR => self.reg_sb = value,
64            REG_SC_ADDR => self.reg_sc = value,
65            _ => unreachable!(),
66        }
67    }
68}