1use log::trace;
2
3use crate::interrupt::{InterruptHandler, InterruptFlag};
4use crate::region::*;
5
6const 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 reg_sb: u8,
20 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 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}