Add rx ability to uart
This commit is contained in:
parent
5490a2ffd6
commit
41a450393e
34
Cargo.lock
generated
34
Cargo.lock
generated
|
@ -2,6 +2,40 @@
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lock_api"
|
||||||
|
version = "0.4.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"scopeguard",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "riscv-uefi"
|
name = "riscv-uefi"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"spinning_top",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "scopeguard"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "spinning_top"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d96d2d1d716fb500937168cc09353ffdc7a012be8475ac7308e1bdf0e3923300"
|
||||||
|
dependencies = [
|
||||||
|
"lock_api",
|
||||||
|
]
|
||||||
|
|
|
@ -4,3 +4,4 @@ version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
spinning_top = "0.3.0"
|
||||||
|
|
28
src/main.rs
28
src/main.rs
|
@ -22,6 +22,19 @@ unsafe extern "C" fn _start() -> ! {
|
||||||
// set the stack pointer
|
// set the stack pointer
|
||||||
"la sp, _init_stack_top",
|
"la sp, _init_stack_top",
|
||||||
|
|
||||||
|
"la sp, _init_stack_top",
|
||||||
|
|
||||||
|
// clear the BSS
|
||||||
|
"la t0, _bss_start",
|
||||||
|
"la t1, _bss_end",
|
||||||
|
"bgeu t0, t1, 2f",
|
||||||
|
"1:",
|
||||||
|
"sb zero, 0(t0)",
|
||||||
|
"addi t0, t0, 1",
|
||||||
|
"bne t0, t1, 1b",
|
||||||
|
"2:",
|
||||||
|
// BSS is clear!
|
||||||
|
|
||||||
// "tail-call" to {entry} (call without saving a return address)
|
// "tail-call" to {entry} (call without saving a return address)
|
||||||
"tail {entry}",
|
"tail {entry}",
|
||||||
entry = sym entry, // {entry} refers to the function [entry] below
|
entry = sym entry, // {entry} refers to the function [entry] below
|
||||||
|
@ -30,13 +43,16 @@ unsafe extern "C" fn _start() -> ! {
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" fn entry() -> ! {
|
extern "C" fn entry() -> ! {
|
||||||
// UNSAFE: correct address for QEMU virt device
|
println!("This should not print because the console is not initialised.");
|
||||||
let mut console = unsafe { uart::Device::new(0x1000_0000) };
|
unsafe { uart::init_console(0x1000_0000) };
|
||||||
for byte in "Hello, world!".bytes() {
|
println!("Hello, world!");
|
||||||
console.put(byte);
|
|
||||||
}
|
|
||||||
|
|
||||||
loop {}
|
loop {
|
||||||
|
let c = uart::CONSOLE.lock().as_mut().and_then(uart::Device::get);
|
||||||
|
if let Some(c) = c {
|
||||||
|
print!("{}", c as char);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
|
|
55
src/uart.rs
55
src/uart.rs
|
@ -1,5 +1,9 @@
|
||||||
//! This module provides access to the UART console.
|
//! This module provides access to the UART console.
|
||||||
|
|
||||||
|
use spinning_top::Spinlock;
|
||||||
|
|
||||||
|
pub static CONSOLE: Spinlock<Option<Device>> = Spinlock::new(None);
|
||||||
|
|
||||||
/// Represents an initialised UART device.
|
/// Represents an initialised UART device.
|
||||||
pub struct Device {
|
pub struct Device {
|
||||||
base: usize,
|
base: usize,
|
||||||
|
@ -29,4 +33,55 @@ impl Device {
|
||||||
core::ptr::write_volatile(ptr, character);
|
core::ptr::write_volatile(ptr, character);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets a character from the UART input.
|
||||||
|
pub fn get(&mut self) -> Option<u8> {
|
||||||
|
const READY: u8 = 0b1;
|
||||||
|
|
||||||
|
let ptr = self.base as *mut u8;
|
||||||
|
// SAFETY: Fine as long as base is correct.
|
||||||
|
let lsr = unsafe { ptr.offset(5) };
|
||||||
|
unsafe {
|
||||||
|
if core::ptr::read_volatile(lsr) & READY == READY {
|
||||||
|
Some(core::ptr::read_volatile(ptr))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl core::fmt::Write for Device {
|
||||||
|
fn write_str(&mut self, s: &str) -> core::fmt::Result {
|
||||||
|
for c in s.bytes() {
|
||||||
|
self.put(c);
|
||||||
|
}
|
||||||
|
Ok(()) // there are never errors writing to UART :)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialise the UART debugging console.
|
||||||
|
/// # Safety
|
||||||
|
/// `base` must point to the base address of a UART device.
|
||||||
|
pub unsafe fn init_console(base: usize) {
|
||||||
|
let mut console = CONSOLE.lock();
|
||||||
|
*console = Some(unsafe { Device::new(base) });
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Prints a formatted string to the [CONSOLE].
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! print {
|
||||||
|
($($arg:tt)*) => ({
|
||||||
|
use core::fmt::Write;
|
||||||
|
$crate::uart::CONSOLE.lock().as_mut().map(|writer| {
|
||||||
|
writer.write_fmt(format_args!($($arg)*)).unwrap()
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// println prints a formatted string to the [CONSOLE] with a trailing newline character.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! println {
|
||||||
|
($fmt:expr) => ($crate::print!(concat!($fmt, "\n")));
|
||||||
|
($fmt:expr, $($arg:tt)*) => ($crate::print!(concat!($fmt, "\n"), $($arg)*));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue