Skip to content

Commit

Permalink
raw_read_write
Browse files Browse the repository at this point in the history
  • Loading branch information
burrbull committed May 16, 2024
1 parent b1ceb6c commit 7746f55
Show file tree
Hide file tree
Showing 7 changed files with 356 additions and 172 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/).

## [Unreleased]

- Add `raw-access` and `raw-read-write` options

- Yet more clean field & register `Debug`

## [v0.33.2] - 2024-05-07
Expand Down
1 change: 1 addition & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ pub struct Config {
pub field_names_for_enums: bool,
pub base_address_shift: u64,
pub raw_access: bool,
pub raw_read_write: bool,
}

#[allow(clippy::upper_case_acronyms)]
Expand Down
7 changes: 7 additions & 0 deletions src/generate/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,11 @@ pub fn render(d: &Device, config: &Config, device_x: &mut String) -> Result<Toke
}

let generic_file = include_str!("generic.rs");
let generic_reg_file = if config.raw_read_write {
include_str!("generic_reg_raw.rs")
} else {
include_str!("generic_reg_vcell.rs")
};
let generic_atomic_file = include_str!("generic_atomic.rs");
if config.generic_mod {
let mut file = File::create(
Expand All @@ -150,6 +155,7 @@ pub fn render(d: &Device, config: &Config, device_x: &mut String) -> Result<Toke
.join("generic.rs"),
)?;
writeln!(file, "{generic_file}")?;
writeln!(file, "{generic_reg_file}")?;
if config.atomics {
if let Some(atomics_feature) = config.atomics_feature.as_ref() {
writeln!(file, "#[cfg(feature = \"{atomics_feature}\")]")?;
Expand All @@ -167,6 +173,7 @@ pub fn render(d: &Device, config: &Config, device_x: &mut String) -> Result<Toke
}
} else {
let mut tokens = syn::parse_file(generic_file)?.into_token_stream();
syn::parse_file(generic_reg_file)?.to_tokens(&mut tokens);
if config.atomics {
if let Some(atomics_feature) = config.atomics_feature.as_ref() {
quote!(#[cfg(feature = #atomics_feature)]).to_tokens(&mut tokens);
Expand Down
172 changes: 0 additions & 172 deletions src/generate/generic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,178 +95,6 @@ pub trait Resettable: RegisterSpec {
}
}

/// This structure provides volatile access to registers.
#[repr(transparent)]
pub struct Reg<REG: RegisterSpec> {
register: vcell::VolatileCell<REG::Ux>,
_marker: marker::PhantomData<REG>,
}

unsafe impl<REG: RegisterSpec> Send for Reg<REG> where REG::Ux: Send {}

impl<REG: RegisterSpec> Reg<REG> {
/// Returns the underlying memory address of register.
///
/// ```ignore
/// let reg_ptr = periph.reg.as_ptr();
/// ```
#[inline(always)]
pub fn as_ptr(&self) -> *mut REG::Ux {
self.register.as_ptr()
}
}

impl<REG: Readable> Reg<REG> {
/// Reads the contents of a `Readable` register.
///
/// You can read the raw contents of a register by using `bits`:
/// ```ignore
/// let bits = periph.reg.read().bits();
/// ```
/// or get the content of a particular field of a register:
/// ```ignore
/// let reader = periph.reg.read();
/// let bits = reader.field1().bits();
/// let flag = reader.field2().bit_is_set();
/// ```
#[inline(always)]
pub fn read(&self) -> R<REG> {
R {
bits: self.register.get(),
_reg: marker::PhantomData,
}
}
}

impl<REG: Resettable + Writable> Reg<REG> {
/// Writes the reset value to `Writable` register.
///
/// Resets the register to its initial state.
#[inline(always)]
pub fn reset(&self) {
self.register.set(REG::RESET_VALUE)
}

/// Writes bits to a `Writable` register.
///
/// You can write raw bits into a register:
/// ```ignore
/// periph.reg.write(|w| unsafe { w.bits(rawbits) });
/// ```
/// or write only the fields you need:
/// ```ignore
/// periph.reg.write(|w| w
/// .field1().bits(newfield1bits)
/// .field2().set_bit()
/// .field3().variant(VARIANT)
/// );
/// ```
/// or an alternative way of saying the same:
/// ```ignore
/// periph.reg.write(|w| {
/// w.field1().bits(newfield1bits);
/// w.field2().set_bit();
/// w.field3().variant(VARIANT)
/// });
/// ```
/// In the latter case, other fields will be set to their reset value.
#[inline(always)]
pub fn write<F>(&self, f: F)
where
F: FnOnce(&mut W<REG>) -> &mut W<REG>,
{
self.register.set(
f(&mut W {
bits: REG::RESET_VALUE & !REG::ONE_TO_MODIFY_FIELDS_BITMAP
| REG::ZERO_TO_MODIFY_FIELDS_BITMAP,
_reg: marker::PhantomData,
})
.bits,
);
}
}

impl<REG: Writable> Reg<REG> {
/// Writes 0 to a `Writable` register.
///
/// Similar to `write`, but unused bits will contain 0.
///
/// # Safety
///
/// Unsafe to use with registers which don't allow to write 0.
#[inline(always)]
pub unsafe fn write_with_zero<F>(&self, f: F)
where
F: FnOnce(&mut W<REG>) -> &mut W<REG>,
{
self.register.set(
f(&mut W {
bits: REG::Ux::default(),
_reg: marker::PhantomData,
})
.bits,
);
}
}

impl<REG: Readable + Writable> Reg<REG> {
/// Modifies the contents of the register by reading and then writing it.
///
/// E.g. to do a read-modify-write sequence to change parts of a register:
/// ```ignore
/// periph.reg.modify(|r, w| unsafe { w.bits(
/// r.bits() | 3
/// ) });
/// ```
/// or
/// ```ignore
/// periph.reg.modify(|_, w| w
/// .field1().bits(newfield1bits)
/// .field2().set_bit()
/// .field3().variant(VARIANT)
/// );
/// ```
/// or an alternative way of saying the same:
/// ```ignore
/// periph.reg.modify(|_, w| {
/// w.field1().bits(newfield1bits);
/// w.field2().set_bit();
/// w.field3().variant(VARIANT)
/// });
/// ```
/// Other fields will have the value they had before the call to `modify`.
#[inline(always)]
pub fn modify<F>(&self, f: F)
where
for<'w> F: FnOnce(&R<REG>, &'w mut W<REG>) -> &'w mut W<REG>,
{
let bits = self.register.get();
self.register.set(
f(
&R {
bits,
_reg: marker::PhantomData,
},
&mut W {
bits: bits & !REG::ONE_TO_MODIFY_FIELDS_BITMAP
| REG::ZERO_TO_MODIFY_FIELDS_BITMAP,
_reg: marker::PhantomData,
},
)
.bits,
);
}
}

impl<REG: Readable> core::fmt::Debug for crate::generic::Reg<REG>
where
R<REG>: core::fmt::Debug
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
core::fmt::Debug::fmt(&self.read(), f)
}
}

#[doc(hidden)]
pub mod raw {
use super::{marker, BitM, FieldSpec, RegisterSpec, Unsafe, Writable};
Expand Down
169 changes: 169 additions & 0 deletions src/generate/generic_reg_raw.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
/// This structure provides unsafe volatile access to registers.
pub struct Reg<REG: RegisterSpec> {
_marker: marker::PhantomData<REG>,
}

unsafe impl<REG: RegisterSpec> Send for Reg<REG> where REG::Ux: Send {}

impl<REG: RegisterSpec> Reg<REG> {
/// Returns the underlying memory address of register.
///
/// ```ignore
/// let reg_ptr = periph.reg.as_ptr();
/// ```
#[inline(always)]
pub fn as_ptr(&self) -> *mut REG::Ux {
(self as *const Self).cast_mut().cast()
}
}

impl<REG: Readable> Reg<REG> {
/// Reads the contents of a `Readable` register.
///
/// You can read the raw contents of a register by using `bits`:
/// ```ignore
/// let bits = periph.reg.read().bits();
/// ```
/// or get the content of a particular field of a register:
/// ```ignore
/// let reader = periph.reg.read();
/// let bits = reader.field1().bits();
/// let flag = reader.field2().bit_is_set();
/// ```
#[inline(always)]
pub unsafe fn read(&self) -> R<REG> {
R {
bits: self.as_ptr().read_volatile(),
_reg: marker::PhantomData,
}
}
}

impl<REG: Resettable + Writable> Reg<REG> {
/// Writes the reset value to `Writable` register.
///
/// Resets the register to its initial state.
#[inline(always)]
pub unsafe fn reset(&self) {
self.as_ptr().write_volatile(REG::RESET_VALUE)
}

/// Writes bits to a `Writable` register.
///
/// You can write raw bits into a register:
/// ```ignore
/// periph.reg.write(|w| unsafe { w.bits(rawbits) });
/// ```
/// or write only the fields you need:
/// ```ignore
/// periph.reg.write(|w| w
/// .field1().bits(newfield1bits)
/// .field2().set_bit()
/// .field3().variant(VARIANT)
/// );
/// ```
/// or an alternative way of saying the same:
/// ```ignore
/// periph.reg.write(|w| {
/// w.field1().bits(newfield1bits);
/// w.field2().set_bit();
/// w.field3().variant(VARIANT)
/// });
/// ```
/// In the latter case, other fields will be set to their reset value.
#[inline(always)]
pub unsafe fn write<F>(&self, f: F)
where
F: FnOnce(&mut W<REG>) -> &mut W<REG>,
{
self.as_ptr().write_volatile(
f(&mut W {
bits: REG::RESET_VALUE & !REG::ONE_TO_MODIFY_FIELDS_BITMAP
| REG::ZERO_TO_MODIFY_FIELDS_BITMAP,
_reg: marker::PhantomData,
})
.bits,
);
}
}

impl<REG: Writable> Reg<REG> {
/// Writes 0 to a `Writable` register.
///
/// Similar to `write`, but unused bits will contain 0.
///
/// # Safety
///
/// Unsafe to use with registers which don't allow to write 0.
#[inline(always)]
pub unsafe fn write_with_zero<F>(&self, f: F)
where
F: FnOnce(&mut W<REG>) -> &mut W<REG>,
{
self.as_ptr().write_volatile(
f(&mut W {
bits: REG::Ux::default(),
_reg: marker::PhantomData,
})
.bits,
);
}
}

impl<REG: Readable + Writable> Reg<REG> {
/// Modifies the contents of the register by reading and then writing it.
///
/// E.g. to do a read-modify-write sequence to change parts of a register:
/// ```ignore
/// periph.reg.modify(|r, w| unsafe { w.bits(
/// r.bits() | 3
/// ) });
/// ```
/// or
/// ```ignore
/// periph.reg.modify(|_, w| w
/// .field1().bits(newfield1bits)
/// .field2().set_bit()
/// .field3().variant(VARIANT)
/// );
/// ```
/// or an alternative way of saying the same:
/// ```ignore
/// periph.reg.modify(|_, w| {
/// w.field1().bits(newfield1bits);
/// w.field2().set_bit();
/// w.field3().variant(VARIANT)
/// });
/// ```
/// Other fields will have the value they had before the call to `modify`.
#[inline(always)]
pub unsafe fn modify<F>(&self, f: F)
where
for<'w> F: FnOnce(&R<REG>, &'w mut W<REG>) -> &'w mut W<REG>,
{
let bits = self.as_ptr().read_volatile();
self.as_ptr().write_volatile(
f(
&R {
bits,
_reg: marker::PhantomData,
},
&mut W {
bits: bits & !REG::ONE_TO_MODIFY_FIELDS_BITMAP
| REG::ZERO_TO_MODIFY_FIELDS_BITMAP,
_reg: marker::PhantomData,
},
)
.bits,
);
}
}

impl<REG: Readable> core::fmt::Debug for crate::generic::Reg<REG>
where
R<REG>: core::fmt::Debug
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
unsafe { core::fmt::Debug::fmt(&self.read(), f) }
}
}
Loading

0 comments on commit 7746f55

Please sign in to comment.