initial commit
Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
commit
02bb380848
18
.gitattributes
vendored
Normal file
18
.gitattributes
vendored
Normal file
@ -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
|
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/target
|
||||
Cargo.lock
|
9
Cargo.toml
Normal file
9
Cargo.toml
Normal file
@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "hardware_register"
|
||||
version = "0.1.0"
|
||||
authors = ["Sean Cross <sean@xobs.io>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
121
src/lib.rs
Normal file
121
src/lib.rs
Normal file
@ -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<T> {
|
||||
base: *mut T,
|
||||
}
|
||||
|
||||
impl<T> CSR<T>
|
||||
where
|
||||
T: std::convert::TryFrom<usize> + std::convert::TryInto<usize> + 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 _);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user