1use core::ptr::{write_volatile, read_volatile};
2
3const IO_BASE: u32 = 0xa10000;
4const IO_DATA: *mut u8 = (IO_BASE + 3) as _;
5const IO_CTRL: *mut u8 = (IO_BASE + 9) as _;
6const IO_TX: *mut u8 = (IO_BASE + 0xf) as _;
7const IO_RX: *mut u8 = (IO_BASE + 0x11) as _;
8const IO_SCTRL: *mut u8 = (IO_BASE + 0x13) as _;
9
10fn read_reg_2(base: *mut u8, idx: u8) -> u8 {
11 unsafe {
12 read_volatile(base.offset((idx * 1) as isize))
13 }
14}
15
16fn write_reg_2(base: *mut u8, idx: u8, v: u8) {
17 unsafe {
18 write_volatile(base.offset((idx * 1) as isize), v);
19 }
20}
21
22fn read_reg_6(base: *mut u8, idx: u8) -> u8 {
23 unsafe {
24 read_volatile(base.offset((idx * 6) as isize))
25 }
26}
27
28fn write_reg_6(base: *mut u8, idx: u8, v: u8) {
29 unsafe {
30 write_volatile(base.offset((idx * 6) as isize), v);
31 }
32}
33
34#[repr(u8)]
36#[derive(Clone, Copy, Debug)]
37pub enum Baud {
38 B4800 = 0b00,
39 B2400 = 0b01,
40 B1200 = 0b10,
41 B300 = 0b11,
42}
43
44#[derive(Clone, Copy, Debug)]
46pub struct SerialStatus(u8);
47
48impl SerialStatus {
49 pub fn is_rx_ready(self) -> bool { (self.0 & 2) != 0 }
51
52 pub fn has_rx_error(self) -> bool { (self.0 & 4) != 0 }
54
55 pub fn is_tx_full(self) -> bool { (self.0 & 1) != 0 }
59
60 pub fn rx_interrupt_enabled(self) -> bool { (self.0 & 8) != 0 }
63
64 pub fn serial_tx(self) -> bool { (self.0 & 0x10) != 0 }
66
67 pub fn serial_rx(self) -> bool { (self.0 & 0x20) != 0 }
69
70 pub fn baud(self) -> Baud {
72 match self.0 >> 6 {
73 0b00 => Baud::B4800,
74 0b01 => Baud::B2400,
75 0b10 => Baud::B1200,
76 _ => Baud::B300,
77 }
78 }
79}
80
81pub struct IOPort(u8);
83
84impl IOPort {
85 pub fn set_pin_directions_raw(&self, directions: u8, enable_int: bool) {
89 let intr = if enable_int { 0x80 } else { 0 };
90 write_reg_2(IO_CTRL, self.0, intr | (directions & 0x7f));
91 }
92
93 pub fn set_pins(&self, values: u8) {
97 write_reg_2(IO_DATA, self.0, values);
98 }
99
100 pub fn get_pins(&self) -> u8 {
104 read_reg_2(IO_DATA, self.0)
105 }
106
107 pub fn configure_serial(&self, sin: bool, sout: bool, rint: bool, baud: Baud) {
113 let mut v = (baud as u8) << 6;
114
115 if sin {
116 v |= 0x20;
117 }
118
119 if sout {
120 v |= 0x10;
121 }
122
123 if rint {
124 v |= 0x80;
125 }
126
127 write_reg_6(IO_SCTRL, self.0, v);
129 }
130
131 pub fn serial_status_raw(&self) -> u8 {
133 read_reg_6(IO_SCTRL, self.0)
134 }
135
136 pub fn serial_read(&self) -> u8 {
138 read_reg_6(IO_RX, self.0)
139 }
140
141 pub fn serial_write(&self, v: u8) {
143 write_reg_6(IO_TX, self.0, v)
144 }
145}
146
147pub fn controller_1() -> IOPort { IOPort(0) }
149
150pub fn controller_2() -> IOPort { IOPort(1) }
152
153pub fn ext() -> IOPort { IOPort(2) }