diff --git a/src/lib.rs b/src/lib.rs index 43f8969..9fb74b7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,12 +17,14 @@ pub struct Field { /// Offset of the first bit in this field offset: usize, + + register: Register, } 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 { + pub const fn new(width: usize, offset: usize, register: Register) -> Field { // assert!(width != 0, "field width cannot be 0"); // assert!((width + offset) < 32, "field with and offset must fit within a 32-bit value"); @@ -62,7 +64,11 @@ impl Field { 31 => 2147483647, _ => 0, }; - Field { mask, offset } + Field { + mask, + offset, + register, + } } } @@ -77,26 +83,32 @@ where pub fn new(base: *mut T) -> Self { CSR { base } } - pub fn r(&mut self, reg: Register, field: Field) -> T { + pub fn r(&mut self, field: Field) -> T { let usize_base: *mut usize = unsafe { core::mem::transmute(&self.base) }; - ((unsafe { usize_base.add(reg.offset).read_volatile() } >> field.offset) & field.mask) + ((unsafe { usize_base.add(field.register.offset).read_volatile() } >> field.offset) + & field.mask) .try_into() .unwrap_or_default() } - pub fn rw(&mut self, reg: Register, field: Field, value: T) { + pub fn rw(&mut self, 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.offset).read_volatile() } & !field.mask; + let previous = + unsafe { usize_base.add(field.register.offset).read_volatile() } & !field.mask; unsafe { usize_base - .add(reg.offset) + .add(field.register.offset) .write_volatile(previous | value_as_usize) }; } - pub fn ow(&mut self, reg: Register, field: Field, value: T) { + pub fn ow(&mut self, 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.offset).write_volatile(value_as_usize) }; + unsafe { + usize_base + .add(field.register.offset) + .write_volatile(value_as_usize) + }; } } @@ -105,33 +117,34 @@ mod tests { pub mod pac { pub mod audio { pub const RX_CTL: crate::Register = crate::Register::new(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 const RX_CTL_ENABLE: crate::Field = crate::Field::new(1, 0, RX_CTL); + pub const RX_CTL_RESET: crate::Field = crate::Field::new(1, 1, RX_CTL); } pub mod uart { pub const RXTX: crate::Register = crate::Register::new(0x00); - pub const RXTX_RXTX: crate::Field = crate::Field::new(8, 0); + pub const RXTX_RXTX: crate::Field = crate::Field::new(8, 0, RXTX); pub const TXFULL: crate::Register = crate::Register::new(0x04); - pub const TXFULL_TXFULL: crate::Field = crate::Field::new(1, 0); + pub const TXFULL_TXFULL: crate::Field = crate::Field::new(1, 0, TXFULL); } } #[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 audio = CSR::new(0x0000_0000 as *mut u32); + audio.r(pac::audio::RX_CTL_ENABLE); + audio.rw(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'); + let mut uart = CSR::new(0x0001_0000 as *mut u8); + uart.ow(pac::uart::RXTX_RXTX, b'a'); + assert_ne!(uart.r(pac::uart::TXFULL_TXFULL), 1); // 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 _); + audio.ow(pac::uart::RXTX_RXTX, b'a' as _); + + // This also compiles, despite the fact that the register offset is + // mismatched and nonsensical + audio.ow(pac::uart::TXFULL_TXFULL, 1); } }