commit 02bb380848dca0b4972c48cbce797ffd2f0b6de9 Author: Sean Cross Date: Sun Sep 27 11:27:18 2020 +0800 initial commit Signed-off-by: Sean Cross diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..d1725ed --- /dev/null +++ b/.gitattributes @@ -0,0 +1,18 @@ +*.py text eol=lf +*.dfu binary +*.png binary +*.jpg binary +*.bin binary +*.elf binary +*.h text eol=lf +*.c text eol=lf +*.s text eol=lf +*.S text eol=lf +README.* text eol=lf +LICENSE text eol=lf +Makefile text eol=lf +*.mk text eol=lf +*.sh text eol=lf +*.ps1 text eol=crlf +.gitignore text eol=lf +.gitattributes text eol=lf \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..96ef6c0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..613a219 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "hardware_register" +version = "0.1.0" +authors = ["Sean Cross "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..10a5343 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,121 @@ +use std::convert::TryInto; +pub struct Field { + /// A bitmask we use to AND to the value, unshifted. + /// E.g. for a width of `3` bits, this mask would be 0b111. + mask: usize, + + /// Offset of the first bit in this field + offset: usize, +} + +impl Field { + /// Define a new CSR field with the given width at a specified + /// offset from the start of the register. + pub const fn new(width: usize, offset: usize) -> Field { + // assert!(width != 0, "field width cannot be 0"); + // assert!((width + offset) < 32, "field with and offset must fit within a 32-bit value"); + + // It would be lovely if we could call `usize::pow()` in a const fn. + let mask = match width { + 0 => 0, + 1 => 1, + 2 => 3, + 3 => 7, + 4 => 15, + 5 => 31, + 6 => 63, + 7 => 127, + 8 => 255, + 9 => 511, + 10 => 1023, + 11 => 2047, + 12 => 4095, + 13 => 8191, + 14 => 16383, + 15 => 32767, + 16 => 65535, + 17 => 131071, + 18 => 262143, + 19 => 524287, + 20 => 1048575, + 21 => 2097151, + 22 => 4194303, + 23 => 8388607, + 24 => 16777215, + 25 => 33554431, + 26 => 67108863, + 27 => 134217727, + 28 => 268435455, + 29 => 536870911, + 30 => 1073741823, + 31 => 2147483647, + _ => 0, + }; + Field { mask, offset } + } +} + +pub struct CSR { + base: *mut T, +} + +impl CSR +where + T: std::convert::TryFrom + std::convert::TryInto + std::default::Default, +{ + pub fn new(base: *mut T) -> Self { + CSR { base } + } + pub fn r(&mut self, reg: usize, field: Field) -> T { + let usize_base: *mut usize = unsafe { core::mem::transmute(&self.base) }; + ((unsafe { usize_base.add(reg).read_volatile() } >> field.offset) & field.mask) + .try_into() + .unwrap_or_default() + } + pub fn rw(&mut self, reg: usize, field: Field, value: T) { + let usize_base: *mut usize = unsafe { core::mem::transmute(&self.base) }; + let value_as_usize: usize = value.try_into().unwrap_or_default() << field.offset; + let previous = unsafe { usize_base.add(reg).read_volatile() } & ! field.mask; + unsafe { usize_base.add(reg).write_volatile(previous | value_as_usize)}; + } + pub fn ow(&mut self, reg: usize, field: Field, value: T) { + let usize_base: *mut usize = unsafe { core::mem::transmute(&self.base) }; + let value_as_usize: usize = value.try_into().unwrap_or_default() << field.offset; + unsafe { usize_base.add(reg).write_volatile(value_as_usize)}; + } +} + +#[cfg(test)] +mod tests { + pub mod pac { + pub mod audio { + pub const RX_CTL: usize = 0x0c; + pub const RX_CTL_ENABLE: crate::Field = crate::Field::new(1, 0); + pub const RX_CTL_RESET: crate::Field = crate::Field::new(1, 1); + } + pub mod uart { + pub const RXTX: usize = 0x00; + pub const RXTX_RXTX: crate::Field = crate::Field::new(8, 0); + pub const TXFULL: usize = 0x04; + pub const TXFULL_TXFULL: crate::Field = crate::Field::new(1, 0); + } + } + #[test] + fn compile_check() { + use super::*; + let mut audio = CSR::new(0x1000_0000 as *mut u32); + audio.r(pac::audio::RX_CTL, pac::audio::RX_CTL_ENABLE); + audio.rw(pac::audio::RX_CTL, pac::audio::RX_CTL_RESET, 1); + + let mut uart = CSR::new(0x1001_0000 as *mut u8); + uart.ow(pac::uart::RXTX, pac::uart::RXTX_RXTX, b'a'); + assert_ne!(uart.r(pac::uart::TXFULL, pac::uart::TXFULL_TXFULL), 1); + + // Note: These also still compile. + uart.ow(pac::uart::RXTX, pac::uart::TXFULL_TXFULL, b'a'); + + // This compiles but requires a cast since `audio` is a pointer to + // u32, whereas `uart` is a pointer to u8. + audio.ow(pac::uart::RXTX, pac::uart::RXTX_RXTX, b'a' as _); + } +}