diff --git a/src/uart.rs b/src/uart.rs new file mode 100644 index 0000000..645911b --- /dev/null +++ b/src/uart.rs @@ -0,0 +1,66 @@ +use core::fmt::{Error, Write}; + +pub struct Uart {} + +impl Uart { + pub fn new() -> Uart { + Uart {} + } + + pub fn putc(&self, c: u8) { + let ptr = 0xE000_1800 as *mut u32; + unsafe { + while ptr.add(1).read_volatile() == 0 {} + ptr.add(0).write_volatile(c as u32); + } + } + + fn get(&self, base_addr: usize) -> Option { + let ptr = 0xE000_1800 as *mut u32; + unsafe { + if ptr.add(2).read_volatile() == 0 { + Some(ptr.add(0).read_volatile() as u8) + } else { + None + } + } + } +} + +// This is a slightly different syntax. Write is this "trait", meaning it is much like +// an interface where we're just guaranteeing a certain function signature. In the Write +// trait, one is absolutely required to be implemented, which is write_str. There are other +// functions, but they all rely on write_str(), so their default implementation is OK for now. +impl Write for Uart { + // The trait Write expects us to write the function write_str + // which looks like: + fn write_str(&mut self, s: &str) -> Result<(), Error> { + for c in s.bytes() { + self.putc(c); + } + // Return that we succeeded. + Ok(()) + } +} + +#[macro_export] +macro_rules! print +{ + ($($args:tt)+) => ({ + use core::fmt::Write; + let _ = write!(crate::uart::Uart::new(), $($args)+); + }); +} +#[macro_export] +macro_rules! println +{ + () => ({ + print!("\r\n") + }); + ($fmt:expr) => ({ + print!(concat!($fmt, "\r\n")) + }); + ($fmt:expr, $($args:tt)+) => ({ + print!(concat!($fmt, "\r\n"), $($args)+) + }); +}