Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#experiment ]Associated Reader/Writer #922

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 53 additions & 13 deletions src/generate/generic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,17 +104,33 @@ pub trait FieldSpec: Sized {
/// Marker for fields with fixed values
pub trait IsEnum: FieldSpec {}

#[doc(hidden)]
pub trait FromBits<U> {
unsafe fn from_bits(b: U) -> Self;
}

#[doc(hidden)]
pub trait ToBits<U> {
fn to_bits(&self) -> U;
}
Comment on lines +108 to +115
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If these traits are not intended to be used externally, maybe we can implement Readable without the extra layer of trait resolution?

I'm thinking along the lines of creating a helper macro to implement the Readable trait on the needed types.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I forgot about inline.
Now it is 7.94 s


/// Trait implemented by readable registers to enable the `read` method.
///
/// Registers marked with `Writable` can be also be `modify`'ed.
pub trait Readable: RegisterSpec {}
pub trait Readable: RegisterSpec {
/// Reader struct associated with register
type Reader: FromBits<Self::Ux>;
}

/// Trait implemented by writeable registers.
///
/// This enables the `write`, `write_with_zero` and `reset` methods.
///
/// Registers marked with `Readable` can be also be `modify`'ed.
pub trait Writable: RegisterSpec {
/// Writer struct associated with register
type Writer: FromBits<Self::Ux> + ToBits<Self::Ux>;

/// Is it safe to write any bits to register
type Safety;

Expand All @@ -140,21 +156,56 @@ pub trait Resettable: RegisterSpec {
}
}

/// Marker for register/field writers which can take any value of specified width
pub struct Safe;
/// You should check that value is allowed to pass to register/field writer marked with this
pub struct Unsafe;
/// Marker for field writers are safe to write in specified inclusive range
pub struct Range<const MIN: u64, const MAX: u64>;
/// Marker for field writers are safe to write in specified inclusive range
pub struct RangeFrom<const MIN: u64>;
/// Marker for field writers are safe to write in specified inclusive range
pub struct RangeTo<const MAX: u64>;

#[doc(hidden)]
pub mod raw {
use super::{marker, BitM, FieldSpec, RegisterSpec, Unsafe, Writable};
use super::{marker, BitM, FieldSpec, FromBits, RegisterSpec, ToBits, Unsafe, Writable};

pub struct R<REG: RegisterSpec> {
pub(crate) bits: REG::Ux,
pub(super) _reg: marker::PhantomData<REG>,
}

impl<REG: RegisterSpec> FromBits<REG::Ux> for R<REG> {
unsafe fn from_bits(bits: REG::Ux) -> Self {
Self {
bits,
_reg: marker::PhantomData,
}
}
}

pub struct W<REG: RegisterSpec> {
///Writable bits
pub(crate) bits: REG::Ux,
pub(super) _reg: marker::PhantomData<REG>,
}

impl<REG: RegisterSpec> FromBits<REG::Ux> for W<REG> {
unsafe fn from_bits(bits: REG::Ux) -> Self {
Self {
bits,
_reg: marker::PhantomData,
}
}
}

impl<REG: RegisterSpec> ToBits<REG::Ux> for W<REG> {
fn to_bits(&self) -> REG::Ux {
self.bits
}
}

pub struct FieldReader<FI = u8>
where
FI: FieldSpec,
Expand Down Expand Up @@ -371,17 +422,6 @@ impl<FI> core::fmt::Debug for BitReader<FI> {
}
}

/// Marker for register/field writers which can take any value of specified width
pub struct Safe;
/// You should check that value is allowed to pass to register/field writer marked with this
pub struct Unsafe;
/// Marker for field writers are safe to write in specified inclusive range
pub struct Range<const MIN: u64, const MAX: u64>;
/// Marker for field writers are safe to write in specified inclusive range
pub struct RangeFrom<const MIN: u64>;
/// Marker for field writers are safe to write in specified inclusive range
pub struct RangeTo<const MAX: u64>;

/// Write field Proxy
pub type FieldWriter<'a, REG, const WI: u8, FI = u8, Safety = Unsafe> =
raw::FieldWriter<'a, REG, WI, FI, Safety>;
Expand Down
24 changes: 6 additions & 18 deletions src/generate/generic_atomic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,9 @@ mod atomic {
#[inline(always)]
pub unsafe fn set_bits<F>(&self, f: F)
where
F: FnOnce(&mut W<REG>) -> &mut W<REG>,
F: FnOnce(&mut REG::Writer) -> &mut REG::Writer,
{
let bits = f(&mut W {
bits: REG::Ux::ZERO,
_reg: marker::PhantomData,
})
.bits;
let bits = f(&mut REG::Writer::from_bits(REG::Ux::ZERO)).to_bits();
REG::Ux::atomic_or(self.register.as_ptr(), bits);
}

Expand All @@ -69,13 +65,9 @@ mod atomic {
#[inline(always)]
pub unsafe fn clear_bits<F>(&self, f: F)
where
F: FnOnce(&mut W<REG>) -> &mut W<REG>,
F: FnOnce(&mut REG::Writer) -> &mut REG::Writer,
{
let bits = f(&mut W {
bits: !REG::Ux::ZERO,
_reg: marker::PhantomData,
})
.bits;
let bits = f(&mut REG::Writer::from_bits(!REG::Ux::ZERO)).to_bits();
REG::Ux::atomic_and(self.register.as_ptr(), bits);
}

Expand All @@ -88,13 +80,9 @@ mod atomic {
#[inline(always)]
pub unsafe fn toggle_bits<F>(&self, f: F)
where
F: FnOnce(&mut W<REG>) -> &mut W<REG>,
F: FnOnce(&mut REG::Writer) -> &mut REG::Writer,
{
let bits = f(&mut W {
bits: REG::Ux::ZERO,
_reg: marker::PhantomData,
})
.bits;
let bits = f(&mut REG::Writer::from_bits(REG::Ux::ZERO)).to_bits();
REG::Ux::atomic_xor(self.register.as_ptr(), bits);
}
}
Expand Down
103 changes: 44 additions & 59 deletions src/generate/generic_reg_vcell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,8 @@ impl<REG: Readable> Reg<REG> {
/// let flag = reader.field2().bit_is_set();
/// ```
#[inline(always)]
pub fn read(&self) -> R<REG> {
R {
bits: self.register.get(),
_reg: marker::PhantomData,
}
pub fn read(&self) -> REG::Reader {
unsafe { REG::Reader::from_bits(self.register.get()) }
}
}

Expand Down Expand Up @@ -76,14 +73,15 @@ impl<REG: Resettable + Writable> Reg<REG> {
#[inline(always)]
pub fn write<F>(&self, f: F) -> REG::Ux
where
F: FnOnce(&mut W<REG>) -> &mut W<REG>,
F: FnOnce(&mut REG::Writer) -> &mut REG::Writer,
{
let value = f(&mut W {
bits: REG::RESET_VALUE & !REG::ONE_TO_MODIFY_FIELDS_BITMAP
| REG::ZERO_TO_MODIFY_FIELDS_BITMAP,
_reg: marker::PhantomData,
})
.bits;
let value = unsafe {
f(&mut REG::Writer::from_bits(
REG::RESET_VALUE & !REG::ONE_TO_MODIFY_FIELDS_BITMAP
| REG::ZERO_TO_MODIFY_FIELDS_BITMAP,
))
.to_bits()
};
self.register.set(value);
value
}
Expand Down Expand Up @@ -119,16 +117,17 @@ impl<REG: Resettable + Writable> Reg<REG> {
#[inline(always)]
pub fn from_write<F, T>(&self, f: F) -> T
where
F: FnOnce(&mut W<REG>) -> T,
F: FnOnce(&mut REG::Writer) -> T,
{
let mut writer = W {
bits: REG::RESET_VALUE & !REG::ONE_TO_MODIFY_FIELDS_BITMAP
| REG::ZERO_TO_MODIFY_FIELDS_BITMAP,
_reg: marker::PhantomData,
let mut writer = unsafe {
REG::Writer::from_bits(
REG::RESET_VALUE & !REG::ONE_TO_MODIFY_FIELDS_BITMAP
| REG::ZERO_TO_MODIFY_FIELDS_BITMAP,
)
};
let result = f(&mut writer);

self.register.set(writer.bits);
self.register.set(writer.to_bits());

result
}
Expand All @@ -145,13 +144,9 @@ impl<REG: Writable> Reg<REG> {
#[inline(always)]
pub unsafe fn write_with_zero<F>(&self, f: F) -> REG::Ux
where
F: FnOnce(&mut W<REG>) -> &mut W<REG>,
F: FnOnce(&mut REG::Writer) -> &mut REG::Writer,
{
let value = f(&mut W {
bits: REG::Ux::ZERO,
_reg: marker::PhantomData,
})
.bits;
let value = f(&mut REG::Writer::from_bits(REG::Ux::ZERO)).to_bits();
self.register.set(value);
value
}
Expand All @@ -166,16 +161,13 @@ impl<REG: Writable> Reg<REG> {
#[inline(always)]
pub unsafe fn from_write_with_zero<F, T>(&self, f: F) -> T
where
F: FnOnce(&mut W<REG>) -> T,
F: FnOnce(&mut REG::Writer) -> T,
{
let mut writer = W {
bits: REG::Ux::ZERO,
_reg: marker::PhantomData,
};
let mut writer = REG::Writer::from_bits(REG::Ux::ZERO);

let result = f(&mut writer);

self.register.set(writer.bits);
self.register.set(writer.to_bits());

result
}
Expand Down Expand Up @@ -210,20 +202,18 @@ impl<REG: Readable + Writable> Reg<REG> {
#[inline(always)]
pub fn modify<F>(&self, f: F) -> REG::Ux
where
for<'w> F: FnOnce(&R<REG>, &'w mut W<REG>) -> &'w mut W<REG>,
for<'w> F: FnOnce(&REG::Reader, &'w mut REG::Writer) -> &'w mut REG::Writer,
{
let bits = self.register.get();
let value = 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;
let value = unsafe {
f(
&REG::Reader::from_bits(bits),
&mut REG::Writer::from_bits(
bits & !REG::ONE_TO_MODIFY_FIELDS_BITMAP | REG::ZERO_TO_MODIFY_FIELDS_BITMAP,
),
)
.to_bits()
};
self.register.set(value);
value
}
Expand Down Expand Up @@ -262,32 +252,27 @@ impl<REG: Readable + Writable> Reg<REG> {
#[inline(always)]
pub fn from_modify<F, T>(&self, f: F) -> T
where
for<'w> F: FnOnce(&R<REG>, &'w mut W<REG>) -> T,
for<'w> F: FnOnce(&REG::Reader, &'w mut REG::Writer) -> T,
{
let bits = self.register.get();
unsafe {
let bits = self.register.get();

let mut writer = W {
bits: bits & !REG::ONE_TO_MODIFY_FIELDS_BITMAP | REG::ZERO_TO_MODIFY_FIELDS_BITMAP,
_reg: marker::PhantomData,
};
let mut writer = REG::Writer::from_bits(
bits & !REG::ONE_TO_MODIFY_FIELDS_BITMAP | REG::ZERO_TO_MODIFY_FIELDS_BITMAP,
);

let result = f(
&R {
bits,
_reg: marker::PhantomData,
},
&mut writer,
);
let result = f(&REG::Reader::from_bits(bits), &mut writer);

self.register.set(writer.bits);
self.register.set(writer.to_bits());

result
result
}
}
}

impl<REG: Readable> core::fmt::Debug for crate::generic::Reg<REG>
impl<REG: Readable> core::fmt::Debug for Reg<REG>
where
R<REG>: core::fmt::Debug,
REG::Reader: core::fmt::Debug,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
core::fmt::Debug::fmt(&self.read(), f)
Expand Down
5 changes: 4 additions & 1 deletion src/generate/register.rs
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,9 @@ pub fn render_register_mod(
let doc = format!("`read()` method returns [`{mod_ty}::R`](R) reader structure",);
mod_items.extend(quote! {
#[doc = #doc]
impl crate::Readable for #regspec_ty {}
impl crate::Readable for #regspec_ty {
type Reader = R;
}
});
}
if can_write {
Expand Down Expand Up @@ -421,6 +423,7 @@ pub fn render_register_mod(
mod_items.extend(quote! {
#[doc = #doc]
impl crate::Writable for #regspec_ty {
type Writer = W;
type Safety = crate::#safe_ty;
#zero_to_modify_fields_bitmap
#one_to_modify_fields_bitmap
Expand Down
Loading