Skip to content

Instantly share code, notes, and snippets.

@jam1garner
Created December 1, 2019 05:06
Show Gist options
  • Save jam1garner/05ffc9db746b92377f2817257847f1dd to your computer and use it in GitHub Desktop.
Save jam1garner/05ffc9db746b92377f2817257847f1dd to your computer and use it in GitHub Desktop.
An example of using ZSTs, Deref/DerefMut, const generics, const fns, and singletons for safe embedded programming in Rust. See thread: https://twitter.com/jam1garner/status/1200946682902589441
#![feature(const_generics)]
#![feature(const_fn)]
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
struct MmioRegister<T: Copy + Sized, const ADDR: usize>(PhantomData<T>);
impl<T: Copy + Sized, const ADDR: usize> MmioRegister<T, ADDR> {
pub const fn new() -> Self {
Self(PhantomData)
}
pub fn read(&self) -> u32 {
unsafe {
*(ADDR as *const u32)
}
}
pub fn write(&mut self, val: u32) {
unsafe {
*(ADDR as *mut u32) = val;
}
}
}
impl<T: Copy + Sized, const ADDR: usize> Deref for MmioRegister<T, ADDR> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe {
&*(ADDR as *const T)
}
}
}
impl<T: Copy + Sized, const ADDR: usize> DerefMut for MmioRegister<T, ADDR> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe {
&mut *(ADDR as *mut T)
}
}
}
struct Uart {
buffer: MmioRegister::<u32, 0xF800_0000>,
flush: MmioRegister::<u32, 0xF800_0004>,
}
impl Uart {
const fn new() -> Self {
Self {
buffer: MmioRegister::new(),
flush: MmioRegister::new(),
}
}
fn write(&mut self, string: &str) {
for c in string.chars() {
*self.buffer = c as _;
}
*self.flush = 1;
}
}
use spin::Mutex;
static UART: Mutex<Option<Uart>> = Mutex::new(Some(Uart::new()));
fn main() {
let mut uart = UART.lock().take().unwrap();
uart.write("test");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment