From 8e8bd228aa41f12b35ca26e63c7bcb1f4dbc8530 Mon Sep 17 00:00:00 2001 From: Adin Ackerman Date: Fri, 8 Nov 2024 12:13:07 -0800 Subject: [PATCH] Update cordic.rs --- src/cordic.rs | 1153 +++++++++++++++++++++++++++++-------------------- 1 file changed, 686 insertions(+), 467 deletions(-) diff --git a/src/cordic.rs b/src/cordic.rs index 05f7c0e2..eb095109 100644 --- a/src/cordic.rs +++ b/src/cordic.rs @@ -15,7 +15,7 @@ //! let mut cordic = dp //! .CORDIC //! .constrain(&mut rcc) -//! .freeze::(); // 16 bit arguments, 32 bit results, compute sine and cosine, 60 iterations +//! .freeze::(); // 16 bit arguments, 32 bit results, 60 iterations, compute sine and cosine //! //! // static operation (zero overhead) //! @@ -38,41 +38,65 @@ //! } //! ``` -use crate::{rcc::Rcc, stm32::CORDIC}; +use crate::{ + rcc::Rcc, + {stm32::cordic::csr, stm32::CORDIC}, +}; use core::marker::PhantomData; -/// Extension trait for constraining the CORDIC peripheral. +/// Extension trait for constraining the Cordic peripheral. pub trait Ext { - /// Constrain the CORDIC peripheral. + /// Constrain the Cordic peripheral. fn constrain(self, rcc: &mut Rcc) -> CordicReset; } impl Ext for CORDIC { #[inline] fn constrain(self, rcc: &mut Rcc) -> CordicReset { - rcc.rb.ahb1enr.modify(|_, w| w.cordicen().set_bit()); + rcc.rb.ahb1enr().modify(|_, w| w.cordicen().set_bit()); - // SAFETY: the resource is assumed to be - // in the "reset" configuration. - unsafe { Cordic::wrap(self) } + // SAFETY: we assume the resource is already + // in a reset state + // BONUS: this line enforces that the + // abstraction is of zero-size + unsafe { core::mem::transmute(()) } } } /// Traits and structures related to data types. pub mod types { + use super::csr; use fixed::traits::Fixed; pub use fixed::types::{I1F15, I1F31}; + pub(crate) mod sealed { + use super::Ext; + + /// Trait for tags to represent Cordic argument or result data. + pub trait Tag { + /// Internal fixed point representation. + type Repr: Ext; + } + } + /// q1.15 fixed point number. pub struct Q15; /// q1.31 fixed point number. pub struct Q31; + impl sealed::Tag for Q15 { + type Repr = I1F15; + } + + impl sealed::Tag for Q31 { + type Repr = I1F31; + } + /// Extension trait for fixed point types. pub trait Ext: Fixed { - /// Type-state representing this type. - type Repr: DataType; + /// Tag representing this type. + type Tag: sealed::Tag; /// Convert to bits of the register width, fn to_register(self) -> u32; @@ -81,58 +105,48 @@ pub mod types { } impl Ext for I1F15 { - type Repr = Q15; + type Tag = Q15; + #[inline] fn to_register(self) -> u32 { self.to_bits() as u16 as u32 } + + #[inline] fn from_register(bits: u32) -> Self { Self::from_bits(bits as u16 as i16) } } impl Ext for I1F31 { - type Repr = Q31; + type Tag = Q31; + #[inline] fn to_register(self) -> u32 { self.to_bits() as u32 } + #[inline] fn from_register(bits: u32) -> Self { Self::from_bits(bits as i32) } } - /// Trait for newtypes to represent CORDIC argument or result data. - pub trait DataType { - /// Internal fixed point representation. - type Inner: Ext; - } - - impl DataType for Q15 { - type Inner = I1F15; - } - - impl DataType for Q31 { - type Inner = I1F31; - } - /// Traits and structures related to argument type-states. - pub mod arg { - pub(crate) type Raw = crate::stm32::cordic::csr::ARGSIZE_A; + pub(crate) mod arg { + use super::{csr, sealed::Tag}; + + pub type Raw = csr::ARGSIZE; /// Trait for argument type-states. - pub(crate) trait State: super::DataType { + pub trait State: Tag { /// Raw representation of the configuration /// in the form of a bitfield variant. const RAW: Raw; /// Configure the resource to be represented /// by this type-state. - #[inline] - fn set(w: crate::stm32::cordic::csr::ARGSIZE_W) { - w.variant(Self::RAW); - } + fn set(w: csr::ARGSIZE_W) -> Self; } macro_rules! impls { @@ -140,6 +154,13 @@ pub mod types { $( impl State for $NAME { const RAW: Raw = Raw::$RAW; + + #[inline] + fn set(w: csr::ARGSIZE_W) -> Self { + w.variant(Self::RAW); + + Self + } } )+ }; @@ -152,21 +173,20 @@ pub mod types { } /// Traits and structures related to result type-states. - pub mod res { - pub(crate) type Raw = crate::stm32::cordic::csr::RESSIZE_A; + pub(crate) mod res { + use super::{csr, sealed::Tag}; + + pub type Raw = csr::RESSIZE; /// Trait for argument type-states. - pub(crate) trait State: super::DataType { + pub trait State: Tag { /// Raw representation of the configuration /// in the form of a bitfield variant. const RAW: Raw; /// Configure the resource to be represented /// by this type-state. - #[inline] - fn set(w: crate::stm32::cordic::csr::RESSIZE_W) { - w.variant(Self::RAW); - } + fn set(w: csr::RESSIZE_W) -> Self; } macro_rules! impls { @@ -174,6 +194,13 @@ pub mod types { $( impl State for $NAME { const RAW: Raw = Raw::$RAW; + + #[inline] + fn set(w: csr::RESSIZE_W) -> Self { + w.variant(Self::RAW); + + Self + } } )+ }; @@ -186,221 +213,344 @@ pub mod types { } } -/// Traits and structures related to function type-states. -pub mod func { - use super::*; - - /// For internal use. A means of indirectly specifying a signature property - /// based solely on the number of elements. - mod data_count { - use super::types; +/// Traits and structures related to data counts (argument or result). +pub(crate) mod reg_count { + use super::{csr, op::data_count, types, PhantomData}; - pub enum Count { - One, - Two, - } + pub struct NReg + where + T: types::sealed::Tag, + Count: data_count::Property, + { + _t: PhantomData, + _count: PhantomData, + } - /// One (primary) function argument/result. - pub struct One; - /// Two (primary and secondary) function arguments/results. - pub struct Two; + pub mod arg { + use super::{csr, data_count, types, NReg, PhantomData}; - pub trait Property - where - T: types::DataType, - { - type Signature: super::signature::Property; + type Raw = csr::NARGS; - const COUNT: Count; + pub(crate) trait State { + fn set(w: csr::NARGS_W) -> Self; } - impl Property for One + impl State for NReg where - T: types::DataType, + Arg: types::arg::State, + Count: data_count::Property, { - type Signature = T::Inner; + #[inline] + fn set(w: csr::NARGS_W) -> Self { + w.variant( + const { + match (Arg::RAW, Count::COUNT) { + (types::arg::Raw::Bits32, data_count::Count::Two) => Raw::Num2, + (_, _) => Raw::Num1, + } + }, + ); + + Self { + _t: PhantomData, + _count: PhantomData, + } + } + } + } - const COUNT: Count = Count::One; + pub mod res { + use super::{csr, data_count, types, NReg, PhantomData}; + + type Raw = csr::NRES; + + pub(crate) trait State { + fn set(w: csr::NRES_W) -> Self; } - impl Property for Two + impl State for NReg where - T: types::DataType, + Res: types::res::State, + Count: data_count::Property, { - type Signature = (T::Inner, T::Inner); - - const COUNT: Count = Count::Two; + #[inline] + fn set(w: csr::NRES_W) -> Self { + w.variant( + const { + match (Res::RAW, Count::COUNT) { + (types::res::Raw::Bits32, data_count::Count::Two) => Raw::Num2, + (_, _) => Raw::Num1, + } + }, + ); + + Self { + _t: PhantomData, + _count: PhantomData, + } + } } } +} - /// Traits and structures related to data counts (argument or result). - pub(crate) mod reg_count { - use super::{super::types, data_count, PhantomData}; +/// Traits and structures related to function scale type-states. +pub mod scale { + use super::csr; - pub struct NReg - where - T: types::DataType, - Count: data_count::Property, - { - _t: PhantomData, - _count: PhantomData, - } + pub(crate) type Raw = u8; - pub mod arg { - use super::{data_count, types, NReg}; + /// Trait for function scale type-states. + pub(crate) trait State { + /// Raw representation of the configuration + /// in the form of a bitfield variant. + const RAW: Raw; - type Raw = crate::stm32::cordic::csr::NARGS_A; + /// Configure the resource to be represented + /// by this type-state. + fn set(w: csr::SCALE_W) -> Self; + } - pub(crate) trait State { - fn set(w: crate::stm32::cordic::csr::NARGS_W); - } + /// Scale of 0. + pub struct N0; + /// Scale of 1. + pub struct N1; + /// Scale of 2. + pub struct N2; + /// Scale of 3. + pub struct N3; + /// Scale of 4. + pub struct N4; + /// Scale of 5. + pub struct N5; + /// Scale of 6. + pub struct N6; + /// Scale of 7. + pub struct N7; - impl State for NReg - where - Arg: types::arg::State, - Count: data_count::Property, - { - fn set(w: crate::stm32::cordic::csr::NARGS_W) { - w.variant( - const { - match (Arg::RAW, Count::COUNT) { - (types::arg::Raw::Bits32, data_count::Count::Two) => Raw::Num2, - (_, _) => Raw::Num1, - } - }, - ); + macro_rules! impls { + ( $( ($NAME:ident, $BITS:expr) $(,)? )+ ) => { + $( + impl State for $NAME { + const RAW: u8 = $BITS; + + #[inline] + fn set(w: csr::SCALE_W) -> Self { + // SAFETY: all bits are valid + unsafe { w.bits(::RAW) }; + + Self + } } - } - } + )+ + }; + } - pub mod res { - use super::{data_count, types, NReg}; + impls! { + (N0, 0), + (N1, 1), + (N2, 2), + (N3, 3), + (N4, 4), + (N5, 5), + (N6, 6), + (N7, 7), + } +} - type Raw = crate::stm32::cordic::csr::NRES_A; +/// Traits and structures related to precision type-states. +pub mod prec { + use super::csr; - pub(crate) trait State { - fn set(w: crate::stm32::cordic::csr::NRES_W); - } + /// Trait for precision type-states. + pub(crate) trait State { + /// Bit representation of the precision. + const BITS: u8; - impl State for NReg - where - Res: types::res::State, - Count: data_count::Property, - { - fn set(w: crate::stm32::cordic::csr::NRES_W) { - w.variant( - const { - match (Res::RAW, Count::COUNT) { - (types::res::Raw::Bits32, data_count::Count::Two) => Raw::Num2, - (_, _) => Raw::Num1, - } - }, - ); + /// Configure the resource to be represented + /// by this type-state. + fn set(w: csr::PRECISION_W) -> Self; + } + + /// 4 iterations. + pub struct P4; + /// 8 iterations. + pub struct P8; + /// 12 iterations. + pub struct P12; + /// 16 iterations. + pub struct P16; + /// 20 iterations. + pub struct P20; + /// 24 iterations. + pub struct P24; + /// 28 iterations. + pub struct P28; + /// 32 iterations. + pub struct P32; + /// 36 iterations. + pub struct P36; + /// 40 iterations. + pub struct P40; + /// 44 iterations. + pub struct P44; + /// 48 iterations. + pub struct P48; + /// 52 iterations. + pub struct P52; + /// 56 iterations. + pub struct P56; + /// 60 iterations. + pub struct P60; + + macro_rules! impls { + ( $( ($NAME:ident, $BITS:expr) $(,)? )+ ) => { + $( + impl State for $NAME { + const BITS: u8 = $BITS; + + #[inline] + fn set(w: csr::PRECISION_W) -> Self { + // SAFETY: reliant on valid type-state + // implementations. + unsafe { w.bits(::BITS) }; + + Self + } } - } - } + )+ + }; } - /// Traits and structures related to function scale type-states. - pub mod scale { - pub(crate) type Raw = u8; + impls! { + (P4, 1), + (P8, 2), + (P12, 3), + (P16, 4), + (P20, 5), + (P24, 6), + (P28, 7), + (P32, 8), + (P36, 9), + (P40, 10), + (P44, 11), + (P48, 12), + (P52, 13), + (P56, 14), + (P60, 15), + } +} - /// Trait for function scale type-states. - pub(crate) trait State { - /// Raw representation of the configuration - /// in the form of a bitfield variant. - const RAW: Raw; +/// Traits and structures related to function type-states. +pub(crate) mod func { + use super::csr; - /// Configure the resource to be represented - /// by this type-state. - #[inline] - fn set(w: crate::stm32::cordic::csr::SCALE_W) { - w.bits(::RAW); - } - } + pub type Raw = csr::FUNC; - /// Scale of 0. - pub struct N0; - /// Scale of 1. - pub struct N1; - /// Scale of 2. - pub struct N2; - /// Scale of 3. - pub struct N3; - /// Scale of 4. - pub struct N4; - /// Scale of 5. - pub struct N5; - /// Scale of 6. - pub struct N6; - /// Scale of 7. - pub struct N7; + /// Trait for function type-states. + pub trait State { + /// Raw representation of the function. + const RAW: Raw; - macro_rules! impls { - ( $( ($NAME:ident, $BITS:expr) $(,)? )+ ) => { - $( - impl State for $NAME { - const RAW: u8 = $BITS; + /// Configure the resource to be represented + /// by this type-state. + fn set(w: csr::FUNC_W) -> Self; + } + + pub struct Cos; + pub struct Sin; + pub struct ATan2; + pub struct Magnitude; + pub struct ATan; + pub struct CosH; + pub struct SinH; + pub struct ATanH; + pub struct Ln; + pub struct Sqrt; + + macro_rules! impls { + ( $( ($NAME:ident, $RAW:ident) $(,)? )+ ) => { + $( + impl State for $NAME { + const RAW: Raw = Raw::$RAW; + + #[inline] + fn set(w: csr::FUNC_W) -> Self { + w.variant(Self::RAW); + + Self } - )+ - }; - } + } + )+ + }; + } - impls! { - (N0, 0), - (N1, 1), - (N2, 2), - (N3, 3), - (N4, 4), - (N5, 5), - (N6, 6), - (N7, 7), - } + impls! { + (Cos, Cosine), + (Sin, Sine), + (ATan2, Phase), + (Magnitude, Modulus), + (ATan, Arctangent), + (CosH, HyperbolicCosine), + (SinH, HyperbolicSine), + (ATanH, Arctanh), + (Ln, NaturalLogarithm), + (Sqrt, SquareRoot), } +} + +/// Traits and structures related to operating the Cordic. +pub mod op { + use core::marker::PhantomData; - /// Traits and structures related to the function signature. - pub mod signature { - use super::{data_count, reg_count, types}; + use super::{func, prec, reg_count, scale, types, Cordic}; + + /// Traits and structures related to the operation signature. + pub(crate) mod signature { + use super::types; use types::arg::State as _; use types::res::State as _; - type WData = crate::stm32g4::Reg; - type RData = crate::stm32g4::Reg; + type WData = crate::stm32::cordic::WDATA; + type RData = crate::stm32::cordic::RDATA; - /// The signature is a property of the function type-state. + /// The signature is a property of the operation type-state. pub trait Property where T: types::Ext, { - /// Number of register operations required. - type NReg; - /// Write arguments to the argument register. - fn write(self, reg: &WData) + /// + /// # Safety: + /// Cordic must be configured to expect the + /// correct number of register writes. + unsafe fn write(self, reg: &WData) where - T::Repr: types::arg::State; + T::Tag: types::arg::State; /// Read results from the result register. - fn read(reg: &RData) -> Self + /// + /// # Safety: + /// Cordic must be configured to expect the + /// correct number of register reades. + unsafe fn read(reg: &RData) -> Self where - T::Repr: types::res::State; + T::Tag: types::res::State; } impl Property for T where T: types::Ext, { - type NReg = reg_count::NReg; - - fn write(self, reg: &WData) + #[inline] + unsafe fn write(self, reg: &WData) where - T::Repr: types::arg::State, + T::Tag: types::arg::State, { - let data = match const { T::Repr::RAW } { + let data = match const { T::Tag::RAW } { types::arg::Raw::Bits16 => { // $RM0440 17.4.2 // since we are only using the lower half of the register, - // the CORDIC **will** read the upper half if the function + // the Cordic **will** read the upper half if the function // accepts two arguments, so we fill it with +1 as per the // stated default. self.to_register() | (0x7fff << 16) @@ -408,12 +558,14 @@ pub mod func { types::arg::Raw::Bits32 => self.to_register(), }; - reg.write(|w| w.arg().bits(data)); + // SAFETY: all bits are valid + reg.write(|w| unsafe { w.arg().bits(data) }); } - fn read(reg: &RData) -> Self + #[inline] + unsafe fn read(reg: &RData) -> Self where - T::Repr: types::res::State, + T::Tag: types::res::State, { T::from_register(reg.read().res().bits()) } @@ -423,34 +575,37 @@ pub mod func { where T: types::Ext, { - type NReg = reg_count::NReg; - - fn write(self, reg: &WData) + #[inline] + unsafe fn write(self, reg: &WData) where - T::Repr: types::arg::State, + T::Tag: types::arg::State, { let (primary, secondary) = self; - match const { T::Repr::RAW } { + match const { T::Tag::RAW } { types::arg::Raw::Bits16 => { // $RM0440 17.4.2 - reg.write(|w| { + // SAFETY: all bits are valid + reg.write(|w| unsafe { w.arg() .bits(primary.to_register() | (secondary.to_register() << 16)) }); } types::arg::Raw::Bits32 => { - reg.write(|w| w.arg().bits(primary.to_register())); - reg.write(|w| w.arg().bits(secondary.to_register())); + // SAFETY: all bits are valid + reg.write(|w| unsafe { w.arg().bits(primary.to_register()) }); + // SAFETY: all bits are valid + reg.write(|w| unsafe { w.arg().bits(secondary.to_register()) }); } }; } - fn read(reg: &RData) -> Self + #[inline] + unsafe fn read(reg: &RData) -> Self where - T::Repr: types::res::State, + T::Tag: types::res::State, { - match const { T::Repr::RAW } { + match const { T::Tag::RAW } { types::res::Raw::Bits16 => { let data = reg.read().res().bits(); @@ -469,69 +624,131 @@ pub mod func { } } - pub(crate) type Raw = crate::stm32::cordic::csr::FUNC_A; + /// For internal use. A means of indirectly specifying a signature property + /// based solely on the number of elements. + pub(crate) mod data_count { + use super::types; - /// Trait for function type-states. - pub trait State { - /// Raw representation of the function. - const RAW: Raw; + pub enum Count { + One, + Two, + } - /// Configure the resource to be represented - /// by this type-state. - #[inline] - fn set(w: crate::stm32::cordic::csr::FUNC_W) { - w.variant(Self::RAW); + pub struct One; + pub struct Two; + + pub trait Property + where + T: types::sealed::Tag, + { + type Signature: super::signature::Property; + + const COUNT: Count; + } + + impl Property for One + where + T: types::sealed::Tag, + { + type Signature = T::Repr; + + const COUNT: Count = Count::One; + } + + impl Property for Two + where + T: types::sealed::Tag, + { + type Signature = (T::Repr, T::Repr); + + const COUNT: Count = Count::Two; + } + } + + pub(crate) mod sealed { + use super::types; + + /// An operation is a feature of the Cordic. + /// + /// Operations are permutations of: + /// - nargs + /// - nres + /// - scale + /// - func + pub trait Feature { + /// The required argument register writes. + type NArgs + where + Arg: types::arg::State + types::sealed::Tag; + /// The required result register reads. + type NRes + where + Res: types::res::State + types::sealed::Tag; + /// The scale to be applied. + type Scale; + /// The function to evaluate. + type Func; + + /// The number of arguments required. + type ArgCount; + /// The number of results produced. + type ResCount; } } - /// Define specific combinations - /// of states and properties for each function. - pub trait Feature: State + /// An operation of the Cordic. + /// + /// Enables writing and reading values + /// to and from the Cordic. + #[allow(unused)] + struct Operation<'a, Arg, Res, Op> where Arg: types::arg::State, Res: types::res::State, + Op: sealed::Feature, { - /// The number of arguments required. - type Arguments: signature::Property; - /// The number of arguments produced. - type Results: signature::Property; - - /// The operation to perform. - type Op: State; - /// The scale to be applied. - type Scale: scale::State; - /// The required argument register writes. - type NArgs: reg_count::arg::State; - /// The required result register reads. - type NRes: reg_count::res::State; - } - - impl Cordic + nargs: &'a Op::NArgs, + nres: &'a Op::NRes, + scale: &'a Op::Scale, + func: &'a Op::Func, + } + + impl<'a, Arg, Res, Op> Operation<'a, Arg, Res, Op> where Arg: types::arg::State, Res: types::res::State, - Func: Feature, - Prec: prec::State, - Func::Arguments: signature::Property, - Func::Results: signature::Property, + Op: sealed::Feature, { - /// Start the configured operation. - pub fn start(&mut self, args: Func::Arguments) { - use signature::Property as _; - - args.write(&self.rb.wdata); + /// Write arguments to the argument register. + #[inline] + fn write(&mut self, args: Args, reg: &crate::stm32::cordic::WDATA) + where + Arg: types::sealed::Tag, + Args: signature::Property, + Op::ArgCount: data_count::Property, + { + // SAFETY: Cordic is necessarily configured properly if + // an instance of `Operation` exists. + unsafe { + signature::Property::::write(args, reg); + } } - /// Get the result of an operation. - pub fn result(&mut self) -> Func::Results { - use signature::Property as _; - - Func::Results::read(&self.rb.rdata) + /// Read results from the result register. + #[inline] + fn read( + &mut self, + reg: &crate::stm32::cordic::RDATA, + ) -> >::Signature + where + Op::ResCount: data_count::Property, + { + // SAFETY: Cordic is necessarily configured properly if + // an instance of `Operation` exists. + unsafe { signature::Property::::read(reg) } } } - // function types with argument count encoded - /// Cosine of an angle theta divided by pi. pub struct Cos; /// Sine of an angle theta divided by pi. @@ -578,50 +795,42 @@ pub mod func { } macro_rules! impls { - ( $( ($NAME:ident < $SCALE:ident >, $RAW:ident, $NARGS:ident, $NRES:ident, start( $($START_PARAM:ident),+ )) $(,)?)+ ) => { + ( $( ($TAG:ident<$SCALE:ident>, $NARGS:ident, $NRES:ident, $FUNC:ident) $(,)?)+ ) => { $( - impl State for $NAME { - const RAW: Raw = Raw::$RAW; - } - - impl Feature for $NAME - where - Arg: types::arg::State, - Res: types::res::State, + impl sealed::Feature for $TAG { - type Arguments = >::Signature; - type Results = >::Signature; - - type Op = Self; + type NArgs = reg_count::NReg + where + Arg: types::arg::State + types::sealed::Tag; + type NRes = reg_count::NReg + where + Res: types::res::State + types::sealed::Tag; type Scale = scale::$SCALE; - type NArgs = >::NReg; - type NRes = >::NReg; + type Func = func::$FUNC; + + type ArgCount = data_count::$NARGS; + type ResCount = data_count::$NRES; } )+ }; } macro_rules! impls_multi_scale { - // root / config (almost identical to single scale) - ( $( ($NAME:ident < $( $SCALE:ident $(,)? )+ >, $RAW:ident, $NARGS:ident, $NRES:ident, start $START_PARAM:tt ) $(,)?)+ ) => { + ( $( ($TAG:ident<$($SCALE:ident $(,)?)+>, $NARGS:ident, $NRES:ident, $FUNC:ident) $(,)?)+ ) => { $( $( - impl State for $NAME { - const RAW: Raw = Raw::$RAW; - } - - impl Feature for $NAME - where - Arg: types::arg::State, - Res: types::res::State, - { - type Arguments = >::Signature; - type Results = >::Signature; - - type Op = Self; + impl sealed::Feature for $TAG { + type NArgs = reg_count::NReg + where + Arg: types::arg::State + types::sealed::Tag; + type NRes = reg_count::NReg + where + Res: types::res::State + types::sealed::Tag; type Scale = scale::$SCALE; - type NArgs = >::NReg; - type NRes = >::NReg; + type Func = func::$FUNC; + + type ArgCount = data_count::$NARGS; + type ResCount = data_count::$NRES; } )+ )+ @@ -629,194 +838,197 @@ pub mod func { } impls! { - (Cos, Cosine, One, One, start(angle)), - (Sin, Sine, One, One, start(angle)), - (SinCos, Sine, One, Two, start(angle)), - (CosM, Cosine, Two, One, start(angle, modulus)), - (SinM, Sine, Two, One, start(angle, modulus)), - (SinCosM, Sine, Two, Two, start(angle, modulus)), - (ATan2, Phase, Two, One, start(x, y)), - (Magnitude, Modulus, Two, One, start(x, y)), - (ATan2Magnitude, Phase, Two, Two, start(x, y)), - (CosH, HyperbolicCosine, One, One, start(x)), - (SinH, HyperbolicSine, One, One, start(x)), - (SinHCosH, HyperbolicSine, One, Two, start(x)), - (ATanH, Arctanh, One, One, start(x)), + (Cos, One, One, Cos), + (Sin, One, One, Sin), + (SinCos, One, Two, Sin), + (CosM, Two, One, Cos), + (SinM, Two, One, Sin), + (SinCosM, Two, Two, Sin), + (ATan2, Two, One, ATan2), + (Magnitude, Two, One, Magnitude), + (ATan2Magnitude, Two, Two, ATan2), + (CosH, One, One, CosH), + (SinH, One, One, SinH), + (SinHCosH, One, Two, SinH), + (ATanH, One, One, ATan), } impls_multi_scale! { - (ATan, Arctangent, One, One, start(x)), - (Ln, NaturalLogarithm, One, One, start(x)), - (Sqrt, SquareRoot, One, One, start(x)), + (ATan, One, One, ATan), + (Ln, One, One, Ln), + (Sqrt, One, One, Sqrt), + } + + impl Cordic + where + Arg: types::arg::State, + Res: types::res::State, + Prec: prec::State, + Op: sealed::Feature, + { + /// Start the configured operation. + #[inline] + pub fn start(&mut self, args: >::Signature) + where + Op::ArgCount: data_count::Property, + { + let config = &self.config; + let mut op = Operation:: { + nargs: &config.nargs, + nres: &config.nres, + scale: &config.scale, + func: &config.func, + }; + + op.write(args, self.rb.wdata()); + } + + /// Get the result of an operation. + #[inline] + pub fn result(&mut self) -> >::Signature + where + Op::ResCount: data_count::Property, + { + let config = &self.config; + let mut op = Operation:: { + nargs: &config.nargs, + nres: &config.nres, + scale: &config.scale, + func: &config.func, + }; + + op.read(self.rb.rdata()) + } } /// Traits and structures for dynamic function operation. pub mod dynamic { - use super::{prec, signature, types, Cordic, Feature}; + use super::{ + super::{prec, reg_count, Cordic}, + data_count, func, scale, + sealed::Feature, + types, Operation, + }; - /// Any function can be invoked with this type-state. + /// Any operation can be invoked with this type-state. pub struct Any; + impl Feature for Any { + type NArgs = () + where + Arg: types::arg::State + types::sealed::Tag; + type NRes = () + where + Res: types::res::State + types::sealed::Tag; + type Scale = (); + type Func = (); + + type ArgCount = (); + type ResCount = (); + } + /// A Cordic in dynamic mode. pub trait Mode where Arg: types::arg::State, Res: types::res::State, { - /// Run a function with provided arguments and get the result. + /// Run an operation with provided arguments and get the result. /// /// *Note: This employs the polling strategy. /// For less overhead, use static operations.* - fn run(&mut self, args: Func::Arguments) -> Func::Results + fn run( + &mut self, + args: >::Signature, + ) -> >::Signature where - Func: Feature; + Op: Feature, + Op::NArgs: reg_count::arg::State, + Op::NRes: reg_count::res::State, + Op::Scale: scale::State, + Op::Func: func::State, + Op::ArgCount: data_count::Property, + Op::ResCount: data_count::Property; } - impl Mode for Cordic + impl Mode for Cordic where Arg: types::arg::State, Res: types::res::State, Prec: prec::State, { - fn run(&mut self, args: Func::Arguments) -> Func::Results + #[inline] + fn run( + &mut self, + args: >::Signature, + ) -> >::Signature where - Func: Feature, + Op: Feature, + Op::NArgs: reg_count::arg::State, + Op::NRes: reg_count::res::State, + Op::Scale: scale::State, + Op::Func: func::State, + Op::ArgCount: data_count::Property, + Op::ResCount: data_count::Property, { - use signature::Property as _; - - self.apply_config::(); + use func::State as _; + use reg_count::{arg::State as _, res::State as _}; + use scale::State as _; + + let (nargs, nres, scale, func) = self.rb.csr().from_modify(|_, w| { + ( + Op::NArgs::set(w.nargs()), + Op::NRes::set(w.nres()), + Op::Scale::set(w.scale()), + Op::Func::set(w.func()), + ) + }); + + let mut op = Operation:: { + nargs: &nargs, + nres: &nres, + scale: &scale, + func: &func, + }; - args.write(&self.rb.wdata); - self.when_ready(|cordic| Func::Results::read(&cordic.rb.rdata)) + op.write(args, self.rb.wdata()); + self.when_ready(|cordic| op.read(cordic.rb.rdata())) } } } } -/// Traits and structures related to precision type-states. -pub mod prec { - /// Trait for precision type-states. - pub(crate) trait State { - /// Bit representation of the precision. - const BITS: u8; - - /// Configure the resource to be represented - /// by this type-state. - fn set(w: crate::stm32::cordic::csr::PRECISION_W); - } - - /// 4 iterations. - pub struct P4; - /// 8 iterations. - pub struct P8; - /// 12 iterations. - pub struct P12; - /// 16 iterations. - pub struct P16; - /// 20 iterations. - pub struct P20; - /// 24 iterations. - pub struct P24; - /// 28 iterations. - pub struct P28; - /// 32 iterations. - pub struct P32; - /// 36 iterations. - pub struct P36; - /// 40 iterations. - pub struct P40; - /// 44 iterations. - pub struct P44; - /// 48 iterations. - pub struct P48; - /// 52 iterations. - pub struct P52; - /// 56 iterations. - pub struct P56; - /// 60 iterations. - pub struct P60; - - macro_rules! impls { - ( $( ($NAME:ident, $BITS:expr) $(,)? )+ ) => { - $( - impl State for $NAME { - const BITS: u8 = $BITS; - - #[inline] - fn set(w: crate::stm32::cordic::csr::PRECISION_W) { - // SAFETY: reliant on valid type-state - // implementations. - unsafe { w.bits(::BITS) }; - } - } - )+ - }; - } - - impls! { - (P4, 1), - (P8, 2), - (P12, 3), - (P16, 4), - (P20, 5), - (P24, 6), - (P28, 7), - (P32, 8), - (P36, 9), - (P40, 10), - (P44, 11), - (P48, 12), - (P52, 13), - (P56, 14), - (P60, 15), - } +/// Configuration for the Cordic. +struct Config { + arg: Arg, + res: Res, + nargs: NArgs, + nres: NRes, + scale: Scale, + prec: Prec, + func: Func, } /// Cordic co-processor interface. -pub struct Cordic +pub struct Cordic where Arg: types::arg::State, Res: types::res::State, Prec: prec::State, + Op: op::sealed::Feature, { rb: CORDIC, - _arg_size: PhantomData, - _res_size: PhantomData, - _func: PhantomData, - _prec: PhantomData, + config: Config, Op::NRes, Op::Scale, Prec, Op::Func>, } // root impl -impl Cordic +impl Cordic where Arg: types::arg::State, Res: types::res::State, Prec: prec::State, + Op: op::sealed::Feature, { - fn apply_config(&mut self) - where - NewArg: types::arg::State, - NewRes: types::res::State, - NewFunc: func::Feature, - NewPrec: prec::State, - { - self.rb.csr.write(|w| { - use func::reg_count::arg::State as _; - use func::reg_count::res::State as _; - use func::scale::State as _; - - NewArg::set(w.argsize()); - NewRes::set(w.ressize()); - NewPrec::set(w.precision()); - NewFunc::set(w.func()); - NewFunc::NArgs::set(w.nargs()); - NewFunc::NRes::set(w.nres()); - NewFunc::Scale::set(w.scale()); - - w - }); - } - /// Configure the resource as dictated by the resulting /// type-states. The produced binding represents /// a frozen configuration, since it is represented @@ -826,26 +1038,43 @@ where /// /// *Note: The configuration is inferred from context because /// it is represented by generic type-states.* - pub fn freeze( - mut self, - ) -> Cordic + #[inline] + pub fn freeze(self) -> Cordic where NewArg: types::arg::State, NewRes: types::res::State, - NewFunc: func::Feature, NewPrec: prec::State, + NewOp: op::sealed::Feature, + NewOp::NArgs: reg_count::arg::State, + NewOp::NRes: reg_count::res::State, + NewOp::Scale: scale::State, + NewOp::Func: func::State, { - self.apply_config::(); + use func::State as _; + use reg_count::arg::State as _; + use reg_count::res::State as _; + use scale::State as _; + + let config = self.rb.csr().from_modify(|_, w| Config { + arg: NewArg::set(w.argsize()), + res: NewRes::set(w.ressize()), + nargs: NewOp::NArgs::set(w.nargs()), + nres: NewOp::NRes::set(w.nres()), + scale: NewOp::Scale::set(w.scale()), + prec: NewPrec::set(w.precision()), + func: NewOp::Func::set(w.func()), + }); - // SAFETY: the resource has been configured - // to represent the new type-states. - unsafe { Cordic::wrap(self.rb) } + Cordic { + rb: self.rb, + config, + } } /// Determine whether a result is pending or not. #[inline] pub fn is_ready(&self) -> bool { - self.rb.csr.read().rrdy().bit_is_set() + self.rb.csr().read().rrdy().bit_is_set() } /// Dispatch an operation once a result is @@ -868,93 +1097,83 @@ where /// Convert into a Cordic interface that supports /// runtime function selection. #[inline] - pub fn into_dynamic(self) -> Cordic { - unsafe { Cordic::wrap(self.rb) } - } - - /// Wrap the resource as a noop. - /// - /// # Safety - /// - /// If the resource configuration and - /// type-states are incongruent, the invariance - /// is broken and actions may exhibit - /// undefined behavior. - pub const unsafe fn wrap(rb: CORDIC) -> Self { - Self { - rb, - _arg_size: PhantomData, - _res_size: PhantomData, - _func: PhantomData, - _prec: PhantomData, + pub fn into_dynamic(self) -> Cordic { + Cordic { + rb: self.rb, + config: Config { + arg: self.config.arg, + res: self.config.res, + nargs: (), + nres: (), + scale: (), + prec: self.config.prec, + func: (), + }, } } } /// $RM0440 17.4.1 -pub type CordicReset = Cordic; +pub type CordicReset = Cordic; -// reset -impl Cordic +impl Cordic where Arg: types::arg::State, Res: types::res::State, - Func: func::Feature, Prec: prec::State, + Op: op::sealed::Feature, { - /// Configure the resource back to the "reset" - /// state. #[inline] - fn reset(self) -> CordicReset { + fn into_reset(self) -> CordicReset { self.freeze() } } // listen -impl Cordic +impl Cordic where Arg: types::arg::State, Res: types::res::State, - Func: func::Feature, Prec: prec::State, + Op: op::sealed::Feature, { /// Enable the result ready interrupt. #[inline] pub fn listen(&mut self) { - self.rb.csr.modify(|_, w| w.ien().set_bit()); + self.rb.csr().modify(|_, w| w.ien().set_bit()); } /// Disable the result ready interrupt. #[inline] pub fn unlisten(&mut self) { - self.rb.csr.modify(|_, w| w.ien().clear_bit()); + self.rb.csr().modify(|_, w| w.ien().clear_bit()); } } // release -impl Cordic +impl Cordic where Arg: types::arg::State, Res: types::res::State, - Func: func::Feature, Prec: prec::State, + Op: op::sealed::Feature, { - /// Release the CORDIC resource binding as a noop. + /// Release the Cordic resource binding as a noop. /// /// # Safety /// - /// The CORDIC peripheral is not reset. + /// The Cordic peripheral is not reset. #[inline] pub unsafe fn release(self) -> CORDIC { self.rb } - /// Release the CORDIC resource binding after reset. + /// Release the Cordic resource binding after reset. #[inline] pub fn release_and_reset(self, rcc: &mut Rcc) -> CORDIC { - let reset = self.reset(); + let reset = self.into_reset(); - rcc.rb.ahb1enr.modify(|_, w| w.cordicen().clear_bit()); + rcc.rb.ahb1enr().modify(|_, w| w.cordicen().clear_bit()); // SAFETY: the resource has been reset unsafe { reset.release() }