[del] tock-registers: Replace manual repeated impls with macros

This commit is contained in:
Berkus Decker 2020-11-22 05:11:29 +02:00
parent 0cf8a88f12
commit b3ddfc5665
2 changed files with 71 additions and 163 deletions

View File

@ -11,5 +11,6 @@ rustflags = [
"-C", "target-feature=-fp-armv8", "-C", "target-feature=-fp-armv8",
"-C", "target-cpu=cortex-a53", "-C", "target-cpu=cortex-a53",
"-C", "embed-bitcode=yes", "-C", "embed-bitcode=yes",
"-Z", "macro-backtrace",
] ]
runner = "cargo make test-runner" runner = "cargo make test-runner"

View File

@ -79,32 +79,20 @@ pub trait IntLike:
fn zero() -> Self; fn zero() -> Self;
} }
impl IntLike for u8 { macro_rules! IntLike_impl_for {
( $( $type:ty ),+ $(,)? ) => {
$(
impl IntLike for $type {
fn zero() -> Self { fn zero() -> Self {
0 0
} }
} }
impl IntLike for u16 { )*
fn zero() -> Self { };
0
}
}
impl IntLike for u32 {
fn zero() -> Self {
0
}
}
impl IntLike for u64 {
fn zero() -> Self {
0
}
}
impl IntLike for u128 {
fn zero() -> Self {
0
}
} }
IntLike_impl_for!(u8, u16, u32, u64, u128);
/// Descriptive name for each register. /// Descriptive name for each register.
pub trait RegisterLongName {} pub trait RegisterLongName {}
@ -408,29 +396,19 @@ impl<T: IntLike + fmt::Debug, R: RegisterLongName> fmt::Debug for LocalRegisterC
} }
} }
impl<R: RegisterLongName> From<LocalRegisterCopy<u8, R>> for u8 { macro_rules! From_impl_for {
fn from(r: LocalRegisterCopy<u8, R>) -> u8 { ( $( $type:ty ),+ $(,)? ) => {
$(
impl<R: RegisterLongName> From<LocalRegisterCopy<$type, R>> for $type {
fn from(r: LocalRegisterCopy<$type, R>) -> $type {
r.value r.value
} }
} }
)*
};
}
impl<R: RegisterLongName> From<LocalRegisterCopy<u16, R>> for u16 { From_impl_for!(u8, u16, u32, u64, u128);
fn from(r: LocalRegisterCopy<u16, R>) -> u16 {
r.value
}
}
impl<R: RegisterLongName> From<LocalRegisterCopy<u32, R>> for u32 {
fn from(r: LocalRegisterCopy<u32, R>) -> u32 {
r.value
}
}
impl<R: RegisterLongName> From<LocalRegisterCopy<u64, R>> for u64 {
fn from(r: LocalRegisterCopy<u64, R>) -> u64 {
r.value
}
}
/// In memory volatile register. /// In memory volatile register.
// To successfully alias this structure onto hardware registers in memory, this // To successfully alias this structure onto hardware registers in memory, this
@ -506,6 +484,8 @@ impl<T: IntLike, R: RegisterLongName> InMemoryRegister<T, R> {
} }
/// Specific section of a register. /// Specific section of a register.
///
/// For the Field, the mask is unshifted, ie. the LSB should always be set.
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct Field<T: IntLike, R: RegisterLongName> { pub struct Field<T: IntLike, R: RegisterLongName> {
mask: T, mask: T,
@ -514,6 +494,14 @@ pub struct Field<T: IntLike, R: RegisterLongName> {
} }
impl<T: IntLike, R: RegisterLongName> Field<T, R> { impl<T: IntLike, R: RegisterLongName> Field<T, R> {
pub const fn new(mask: T, shift: usize) -> Field<T, R> {
Field {
mask: mask,
shift: shift,
associated_register: PhantomData,
}
}
/// Get the raw bitmask used by this Field. /// Get the raw bitmask used by this Field.
pub fn mask(&self) -> T { pub fn mask(&self) -> T {
(self.mask as T) << self.shift (self.mask as T) << self.shift
@ -537,66 +525,24 @@ impl<T: IntLike, R: RegisterLongName> Field<T, R> {
} }
} }
// For the Field, the mask is unshifted, ie. the LSB should always be set macro_rules! Field_impl_for {
impl<R: RegisterLongName> Field<u8, R> { ( $( $type:ty ),+ $(,)? ) => {
pub const fn new(mask: u8, shift: usize) -> Field<u8, R> { $(
Field { impl<R: RegisterLongName> Field<$type, R> {
mask: mask, pub fn val(&self, value: $type) -> FieldValue<$type, R> {
shift: shift, FieldValue::<$type, R>::new(self.mask, self.shift, value)
associated_register: PhantomData,
} }
} }
)*
};
}
pub fn val(&self, value: u8) -> FieldValue<u8, R> { Field_impl_for!(u8, u16, u32, u64, u128);
FieldValue::<u8, R>::new(self.mask, self.shift, value)
}
}
impl<R: RegisterLongName> Field<u16, R> {
pub const fn new(mask: u16, shift: usize) -> Field<u16, R> {
Field {
mask: mask,
shift: shift,
associated_register: PhantomData,
}
}
pub fn val(&self, value: u16) -> FieldValue<u16, R> {
FieldValue::<u16, R>::new(self.mask, self.shift, value)
}
}
impl<R: RegisterLongName> Field<u32, R> {
pub const fn new(mask: u32, shift: usize) -> Field<u32, R> {
Field {
mask: mask,
shift: shift,
associated_register: PhantomData,
}
}
pub fn val(&self, value: u32) -> FieldValue<u32, R> {
FieldValue::<u32, R>::new(self.mask, self.shift, value)
}
}
impl<R: RegisterLongName> Field<u64, R> {
pub const fn new(mask: u64, shift: usize) -> Field<u64, R> {
Field {
mask: mask,
shift: shift,
associated_register: PhantomData,
}
}
pub fn val(&self, value: u64) -> FieldValue<u64, R> {
FieldValue::<u64, R>::new(self.mask, self.shift, value)
}
}
/// Values for the specific register fields. /// Values for the specific register fields.
// For the FieldValue, the masks and values are shifted into their actual ///
// location in the register. /// For the FieldValue, the masks and values are shifted into their actual
/// location in the register.
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct FieldValue<T: IntLike, R: RegisterLongName> { pub struct FieldValue<T: IntLike, R: RegisterLongName> {
mask: T, mask: T,
@ -604,11 +550,14 @@ pub struct FieldValue<T: IntLike, R: RegisterLongName> {
associated_register: PhantomData<R>, associated_register: PhantomData<R>,
} }
macro_rules! FieldValue_impl_for {
( $( $type:ty ),+ $(,)? ) => {
$(
// Necessary to split the implementation of new() out because the bitwise // Necessary to split the implementation of new() out because the bitwise
// math isn't treated as const when the type is generic. // math isn't treated as const when the type is generic.
// Tracking issue: https://github.com/rust-lang/rfcs/pull/2632 // Tracking issue: https://github.com/rust-lang/rfcs/pull/2632
impl<R: RegisterLongName> FieldValue<u8, R> { impl<R: RegisterLongName> FieldValue<$type, R> {
pub const fn new(mask: u8, shift: usize, value: u8) -> Self { pub const fn new(mask: $type, shift: usize, value: $type) -> Self {
FieldValue { FieldValue {
mask: mask << shift, mask: mask << shift,
value: (value & mask) << shift, value: (value & mask) << shift,
@ -616,64 +565,22 @@ impl<R: RegisterLongName> FieldValue<u8, R> {
} }
} }
} }
// Necessary to split the implementation of From<> out because of the orphan rule
impl<R: RegisterLongName> From<FieldValue<u8, R>> for u8 { // for foreign trait implementation (see [E0210](https://doc.rust-lang.org/error-index.html#E0210)).
fn from(val: FieldValue<u8, R>) -> u8 { impl<R: RegisterLongName> From<FieldValue<$type, R>> for $type {
fn from(val: FieldValue<$type, R>) -> $type {
val.value val.value
} }
} }
)*
impl<R: RegisterLongName> FieldValue<u16, R> { };
pub const fn new(mask: u16, shift: usize, value: u16) -> Self {
FieldValue {
mask: mask << shift,
value: (value & mask) << shift,
associated_register: PhantomData,
}
}
} }
impl<R: RegisterLongName> From<FieldValue<u16, R>> for u16 { FieldValue_impl_for!(u8, u16, u32, u64, u128);
fn from(val: FieldValue<u16, R>) -> u16 {
val.value
}
}
impl<R: RegisterLongName> FieldValue<u32, R> {
pub const fn new(mask: u32, shift: usize, value: u32) -> Self {
FieldValue {
mask: mask << shift,
value: (value & mask) << shift,
associated_register: PhantomData,
}
}
}
impl<R: RegisterLongName> From<FieldValue<u32, R>> for u32 {
fn from(val: FieldValue<u32, R>) -> u32 {
val.value
}
}
impl<R: RegisterLongName> FieldValue<u64, R> {
pub const fn new(mask: u64, shift: usize, value: u64) -> Self {
FieldValue {
mask: mask << shift,
value: (value & mask) << shift,
associated_register: PhantomData,
}
}
}
impl<R: RegisterLongName> From<FieldValue<u64, R>> for u64 {
fn from(val: FieldValue<u64, R>) -> u64 {
val.value
}
}
impl<T: IntLike, R: RegisterLongName> FieldValue<T, R> { impl<T: IntLike, R: RegisterLongName> FieldValue<T, R> {
/// Get the raw bitmask represented by this FieldValue. /// Get the raw bitmask represented by this FieldValue.
pub fn mask(self) -> T { pub fn mask(&self) -> T {
self.mask as T self.mask as T
} }