Skip to content

Generic Part1 #347

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

Merged
merged 1 commit into from
Aug 2, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
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
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

- `variant()` method for field reader and `Variant` enum for fields with reserved values

- Field readers and writers use one enum where it is possible
### Changed

- Field readers and writers use one enum where it is possible

- Replace register and its reader/writer by generic types

## [v0.15.2] - 2019-07-29

Expand Down
162 changes: 149 additions & 13 deletions src/generate/generic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,27 @@ pub fn render() -> Result<Vec<Tokens>> {
generic_items.push(quote! {
use core::marker;

///This trait shows that register has `read` method
///
///Registers marked with `Writable` can be also `modify`'ed
pub trait Readable {}

///This trait shows that register has `write`, `write_with_zero` and `reset` method
///
///Registers marked with `Readable` can be also `modify`'ed
pub trait Writable {}

///Reset value of the register
///
///This value is initial value for `write` method.
///It can be also directly writed to register by `reset` method.
pub trait ResetValue {
///Register size
type Type;
///Reset value of the register
fn reset_value() -> Self::Type;
}

///Converting enumerated values to bits
pub trait ToBits<N> {
///Conversion method
Expand All @@ -18,23 +39,105 @@ pub fn render() -> Result<Vec<Tokens>> {
});

generic_items.push(quote! {
///Value read from the register
pub struct FR<U, T> {
pub(crate) bits: U,
_reg: marker::PhantomData<T>,
///This structure provides volatile access to register
pub struct Reg<U, REG> {
register: vcell::VolatileCell<U>,
_marker: marker::PhantomData<REG>,
}

impl<U, T, FI> PartialEq<FI> for FR<U, T>
unsafe impl<U: Send, REG> Send for Reg<U, REG> { }

impl<U, REG> Reg<U, REG>
where
U: PartialEq,
FI: ToBits<U>
Self: Readable,
U: Copy
{
fn eq(&self, other: &FI) -> bool {
self.bits.eq(&other._bits())
///Reads the contents of `Readable` register
///
///See [reading](https://rust-embedded.github.io/book/start/registers.html#reading) in book.
#[inline(always)]
pub fn read(&self) -> R<U, Self> {
R {bits: self.register.get(), _reg: marker::PhantomData}
}
}

impl<U, REG> Reg<U, REG>
where
Self: ResetValue<Type=U> + Writable,
U: Copy,
{
///Writes the reset value to `Writable` register
#[inline(always)]
pub fn reset(&self) {
self.register.set(Self::reset_value())
}
}
});

generic_items.push(quote! {
impl<U, REG> Reg<U, REG>
where
Self: ResetValue<Type=U> + Writable,
U: Copy
{
///Writes bits to `Writable` register
///
///See [writing](https://rust-embedded.github.io/book/start/registers.html#writing) in book.
#[inline(always)]
pub fn write<F>(&self, f: F)
where
F: FnOnce(&mut W<U, Self>) -> &mut W<U, Self>
{
self.register.set(f(&mut W {bits: Self::reset_value(), _reg: marker::PhantomData}).bits);
}
}
});

generic_items.push(quote! {
impl<U, REG> Reg<U, REG>
where
Self: Writable,
U: Copy + Default
Copy link
Member

Choose a reason for hiding this comment

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

Is this Default equals to "returns zero"?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, it is for bool, u8, u16 u32 and u64.

Copy link
Member

Choose a reason for hiding this comment

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

Yes, but these types are not enforced I guess

Copy link
Member Author

Choose a reason for hiding this comment

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

They are enforced by size type of register or field.

Copy link
Member

Choose a reason for hiding this comment

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

But it's possible to create a wrapper with the same size and a custom Default impl that returns reset value, for example

Copy link
Member Author

Choose a reason for hiding this comment

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

How? All fields are private. You can get register only from peripheral as it was before.

Copy link
Member

Choose a reason for hiding this comment

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

Hmm, now I see. Thanks.

{
///Writes Zero to `Writable` register
#[inline(always)]
pub fn write_with_zero<F>(&self, f: F)
where
F: FnOnce(&mut W<U, Self>) -> &mut W<U, Self>
{
self.register.set(f(&mut W {bits: U::default(), _reg: marker::PhantomData }).bits);
}
}
});

generic_items.push(quote! {
impl<U, REG> Reg<U, REG>
where
Self: Readable + Writable,
U: Copy,
{
///Modifies the contents of the register
///
///See [modifying](https://rust-embedded.github.io/book/start/registers.html#modifying) in book.
#[inline(always)]
pub fn modify<F>(&self, f: F)
where
for<'w> F: FnOnce(&R<U, Self>, &'w mut W<U, Self>) -> &'w mut W<U, Self>
{
let bits = self.register.get();
self.register.set(f(&R {bits, _reg: marker::PhantomData}, &mut W {bits, _reg: marker::PhantomData}).bits);
}
}
});

impl<U, T> FR<U, T>
generic_items.push(quote! {
///Register/field reader
pub struct R<U, T> {
pub(crate) bits: U,
_reg: marker::PhantomData<T>,
}

impl<U, T> R<U, T>
where
U: Copy
{
Expand All @@ -46,7 +149,7 @@ pub fn render() -> Result<Vec<Tokens>> {
_reg: marker::PhantomData,
}
}
///Read raw bits from field
///Read raw bits from register/field
#[inline(always)]
pub fn bits(&self) -> U {
self.bits
Expand All @@ -55,7 +158,19 @@ pub fn render() -> Result<Vec<Tokens>> {
});

generic_items.push(quote! {
impl<FI> FR<bool, FI> {
impl<U, T, FI> PartialEq<FI> for R<U, T>
where
U: PartialEq,
FI: ToBits<U>
{
fn eq(&self, other: &FI) -> bool {
self.bits.eq(&other._bits())
}
}
});

generic_items.push(quote! {
impl<FI> R<bool, FI> {
///Value of the field as raw bits
#[inline(always)]
pub fn bit(&self) -> bool {
Expand All @@ -74,6 +189,27 @@ pub fn render() -> Result<Vec<Tokens>> {
}
});

generic_items.push(quote! {
///Register writer
pub struct W<U, REG> {
///Writable bits
pub bits: U,
_reg: marker::PhantomData<REG>,
}
});

generic_items.push(quote! {
impl<U, REG> W<U, REG> {
///Writes raw bits to the register
#[inline(always)]
pub fn bits(&mut self, bits: U) -> &mut Self {
self.bits = bits;
self
}
}
});


generic_items.push(quote! {
///Used if enumerated values cover not the whole range
#[derive(Clone,Copy,PartialEq)]
Expand All @@ -88,7 +224,7 @@ pub fn render() -> Result<Vec<Tokens>> {
code.push(quote! {
#[allow(unused_imports)]
use generic::*;
/// Common register and bit access and modify traits
///Common register and bit access and modify traits
pub mod generic {
#(#generic_items)*
}
Expand Down
Loading