lib: rename accessors to reflect register-or-field
Some accessors work on fields, whereas others work on the whole register. Rename the functions to reflect what works where. Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
parent
fe68f64446
commit
5de52c0809
70
src/lib.rs
70
src/lib.rs
@ -19,6 +19,9 @@ pub struct Field {
|
||||
/// Offset of the first bit in this field
|
||||
offset: usize,
|
||||
|
||||
/// A copy of the register address that this field
|
||||
/// is a member of. Ideally this is optimized out by the
|
||||
/// compiler.
|
||||
register: Register,
|
||||
}
|
||||
|
||||
@ -26,6 +29,7 @@ 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, register: Register) -> Field {
|
||||
// Asserts don't work in const fn yet.
|
||||
// assert!(width != 0, "field width cannot be 0");
|
||||
// assert!((width + offset) < 32, "field with and offset must fit within a 32-bit value");
|
||||
|
||||
@ -84,14 +88,26 @@ where
|
||||
pub fn new(base: *mut T) -> Self {
|
||||
CSR { base }
|
||||
}
|
||||
pub fn r(&mut self, field: Field) -> T {
|
||||
|
||||
/// Read the contents of this register
|
||||
pub fn r(&mut self, reg: Register) -> T {
|
||||
let usize_base: *mut usize = unsafe { core::mem::transmute(self.base) };
|
||||
unsafe { usize_base.add(reg.offset).read_volatile() }
|
||||
.try_into()
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
/// Read a field from this CSR
|
||||
pub fn rf(&mut self, field: Field) -> T {
|
||||
let usize_base: *mut usize = unsafe { core::mem::transmute(self.base) };
|
||||
((unsafe { usize_base.add(field.register.offset).read_volatile() } >> field.offset)
|
||||
& field.mask)
|
||||
.try_into()
|
||||
.unwrap_or_default()
|
||||
}
|
||||
pub fn rw(&mut self, field: Field, value: T) {
|
||||
|
||||
/// Read-modify-write a given field in this CSR
|
||||
pub fn rmwf(&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 =
|
||||
@ -102,7 +118,9 @@ where
|
||||
.write_volatile(previous | value_as_usize)
|
||||
};
|
||||
}
|
||||
pub fn ow(&mut self, field: Field, value: T) {
|
||||
|
||||
/// Write a given field without reading it first
|
||||
pub fn wf(&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 {
|
||||
@ -111,6 +129,17 @@ where
|
||||
.write_volatile(value_as_usize)
|
||||
};
|
||||
}
|
||||
|
||||
/// Write the entire contents of a register without reading it first
|
||||
pub fn w(&mut self, reg: Register, value: T) {
|
||||
let usize_base: *mut usize = unsafe { core::mem::transmute(self.base) };
|
||||
let value_as_usize: usize = value.try_into().unwrap_or_default();
|
||||
unsafe {
|
||||
usize_base
|
||||
.add(reg.offset)
|
||||
.write_volatile(value_as_usize)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@ -132,20 +161,41 @@ mod tests {
|
||||
#[test]
|
||||
fn compile_check() {
|
||||
use super::*;
|
||||
let mut audio = CSR::new(0x1000_0000 as *mut u32);
|
||||
audio.r(pac::audio::RX_CTL_ENABLE);
|
||||
audio.rw(pac::audio::RX_CTL_RESET, 1);
|
||||
|
||||
// Audio tests
|
||||
|
||||
// The audio block is a pointer to *mut 32.
|
||||
let mut audio = CSR::new(0x1000_0000 as *mut u32);
|
||||
|
||||
// Read the entire contents of the RX_CTL register
|
||||
audio.r(pac::audio::RX_CTL);
|
||||
|
||||
// Or read just one field
|
||||
audio.rf(pac::audio::RX_CTL_ENABLE);
|
||||
|
||||
// Do a read-modify-write of the specified field
|
||||
audio.rmwf(pac::audio::RX_CTL_RESET, 1);
|
||||
|
||||
// UART tests
|
||||
|
||||
// Create the UART register as a pointer to *mut u8
|
||||
let mut uart = CSR::new(0x1001_0000 as *mut u8);
|
||||
uart.ow(pac::uart::RXTX_RXTX, b'a');
|
||||
assert_ne!(uart.r(pac::uart::TXFULL_TXFULL), 1);
|
||||
|
||||
// Write the RXTX field of the RXTX register
|
||||
uart.wf(pac::uart::RXTX_RXTX, b'a');
|
||||
|
||||
// Or you can write the whole UART register
|
||||
uart.w(pac::uart::RXTX, b'a');
|
||||
assert_ne!(uart.rf(pac::uart::TXFULL_TXFULL), 1);
|
||||
|
||||
// Anomalies
|
||||
|
||||
// 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_RXTX, b'a' as _);
|
||||
audio.wf(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);
|
||||
audio.wf(pac::uart::TXFULL_TXFULL, 1);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user