diff --git a/CHANGELOG.md b/CHANGELOG.md index bbfd8456..75eab9a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/). ## [Unreleased] - Fix when `atomics` features is generated but not enabled +- move hidden structs into module, add register reader/writer links into `SPEC` docs (#736) - removed register writer & reader wrappers, generic `REG` in field writers (#731) - Updated syn to version 2 (#732) - Let readable field fetch doc from svd description (#734) diff --git a/src/generate/generic.rs b/src/generate/generic.rs index c589b149..b91fa694 100644 --- a/src/generate/generic.rs +++ b/src/generate/generic.rs @@ -252,17 +252,114 @@ impl Reg { } } +#[doc(hidden)] +pub mod raw { + use super::{marker, BitM, FieldSpec, RegisterSpec, Unsafe, Writable}; + + pub struct R { + pub(crate) bits: REG::Ux, + pub(super) _reg: marker::PhantomData, + } + + pub struct W { + ///Writable bits + pub(crate) bits: REG::Ux, + pub(super) _reg: marker::PhantomData, + } + + pub struct FieldReader + where + FI: FieldSpec, + { + pub(crate) bits: FI::Ux, + _reg: marker::PhantomData, + } + + impl FieldReader { + /// Creates a new instance of the reader. + #[allow(unused)] + #[inline(always)] + pub(crate) fn new(bits: FI::Ux) -> Self { + Self { + bits, + _reg: marker::PhantomData, + } + } + } + + pub struct BitReader { + pub(crate) bits: bool, + _reg: marker::PhantomData, + } + + impl BitReader { + /// Creates a new instance of the reader. + #[allow(unused)] + #[inline(always)] + pub(crate) fn new(bits: bool) -> Self { + Self { + bits, + _reg: marker::PhantomData, + } + } + } + + pub struct FieldWriter<'a, REG, const WI: u8, const O: u8, FI = u8, Safety = Unsafe> + where + REG: Writable + RegisterSpec, + FI: FieldSpec, + { + pub(crate) w: &'a mut W, + _field: marker::PhantomData<(FI, Safety)>, + } + + impl<'a, REG, const WI: u8, const O: u8, FI, Safety> FieldWriter<'a, REG, WI, O, FI, Safety> + where + REG: Writable + RegisterSpec, + FI: FieldSpec, + { + /// Creates a new instance of the writer + #[allow(unused)] + #[inline(always)] + pub(crate) fn new(w: &'a mut W) -> Self { + Self { + w, + _field: marker::PhantomData, + } + } + } + + pub struct BitWriter<'a, REG, const O: u8, FI = bool, M = BitM> + where + REG: Writable + RegisterSpec, + bool: From, + { + pub(crate) w: &'a mut W, + _field: marker::PhantomData<(FI, M)>, + } + + impl<'a, REG, const O: u8, FI, M> BitWriter<'a, REG, O, FI, M> + where + REG: Writable + RegisterSpec, + bool: From, + { + /// Creates a new instance of the writer + #[allow(unused)] + #[inline(always)] + pub(crate) fn new(w: &'a mut W) -> Self { + Self { + w, + _field: marker::PhantomData, + } + } + } +} + /// Register reader. /// /// Result of the `read` methods of registers. Also used as a closure argument in the `modify` /// method. -pub type R = RRaw; - -#[doc(hidden)] -pub struct RRaw { - pub(crate) bits: REG::Ux, - _reg: marker::PhantomData, -} +pub type R = raw::R; impl R { /// Reads raw bits from register. @@ -287,61 +384,15 @@ where /// Register writer. /// /// Used as an argument to the closures in the `write` and `modify` methods of the register. -pub type W = WRaw; - -#[doc(hidden)] -pub struct WRaw { - ///Writable bits - pub(crate) bits: REG::Ux, - _reg: marker::PhantomData, -} - -#[doc(hidden)] -pub struct FieldReaderRaw -where - FI: FieldSpec -{ - pub(crate) bits: FI::Ux, - _reg: marker::PhantomData, -} - -impl FieldReaderRaw { - /// Creates a new instance of the reader. - #[allow(unused)] - #[inline(always)] - pub(crate) fn new(bits: FI::Ux) -> Self { - Self { - bits, - _reg: marker::PhantomData, - } - } -} - -#[doc(hidden)] -pub struct BitReaderRaw { - pub(crate) bits: bool, - _reg: marker::PhantomData, -} - -impl BitReaderRaw { - /// Creates a new instance of the reader. - #[allow(unused)] - #[inline(always)] - pub(crate) fn new(bits: bool) -> Self { - Self { - bits, - _reg: marker::PhantomData, - } - } -} +pub type W = raw::W; /// Field reader. /// /// Result of the `read` methods of fields. -pub type FieldReader = FieldReaderRaw; +pub type FieldReader = raw::FieldReader; /// Bit-wise field reader -pub type BitReader = BitReaderRaw; +pub type BitReader = raw::BitReader; impl FieldReader { /// Reads raw bits from field. @@ -395,65 +446,12 @@ pub struct Safe; #[doc(hidden)] pub struct Unsafe; -#[doc(hidden)] -pub struct FieldWriterRaw<'a, REG, const WI: u8, const O: u8, FI = u8, Safety = Unsafe> -where - REG: Writable + RegisterSpec, - FI: FieldSpec, -{ - pub(crate) w: &'a mut W, - _field: marker::PhantomData<(FI, Safety)>, -} - -impl<'a, REG, const WI: u8, const O: u8, FI, Safety> - FieldWriterRaw<'a, REG, WI, O, FI, Safety> -where - REG: Writable + RegisterSpec, - FI: FieldSpec, -{ - /// Creates a new instance of the writer - #[allow(unused)] - #[inline(always)] - pub(crate) fn new(w: &'a mut W) -> Self { - Self { - w, - _field: marker::PhantomData, - } - } -} - -#[doc(hidden)] -pub struct BitWriterRaw<'a, REG, const O: u8, FI = bool, M = BitM> -where - REG: Writable + RegisterSpec, - bool: From, -{ - pub(crate) w: &'a mut W, - _field: marker::PhantomData<(FI, M)>, -} - -impl<'a, REG, const O: u8, FI, M> BitWriterRaw<'a, REG, O, FI, M> -where - REG: Writable + RegisterSpec, - bool: From, -{ - /// Creates a new instance of the writer - #[allow(unused)] - #[inline(always)] - pub(crate) fn new(w: &'a mut W) -> Self { - Self { - w, - _field: marker::PhantomData, - } - } -} - /// Write field Proxy with unsafe `bits` pub type FieldWriter<'a, REG, const WI: u8, const O: u8, FI = u8> = - FieldWriterRaw<'a, REG, WI, O, FI, Unsafe>; + raw::FieldWriter<'a, REG, WI, O, FI, Unsafe>; /// Write field Proxy with safe `bits` pub type FieldWriterSafe<'a, REG, const WI: u8, const O: u8, FI = u8> = - FieldWriterRaw<'a, REG, WI, O, FI, Safe>; + raw::FieldWriter<'a, REG, WI, O, FI, Safe>; impl<'a, REG, const WI: u8, const OF: u8, FI> FieldWriter<'a, REG, WI, OF, FI> where @@ -479,7 +477,7 @@ macro_rules! bit_proxy { pub struct $mwv; /// Bit-wise write field proxy - pub type $writer<'a, REG, const O: u8, FI = bool> = BitWriterRaw<'a, REG, O, FI, $mwv>; + pub type $writer<'a, REG, const O: u8, FI = bool> = raw::BitWriter<'a, REG, O, FI, $mwv>; impl<'a, REG, const OF: u8, FI> $writer<'a, REG, OF, FI> where diff --git a/src/generate/peripheral.rs b/src/generate/peripheral.rs index b9ba1aca..5dbfdeb8 100644 --- a/src/generate/peripheral.rs +++ b/src/generate/peripheral.rs @@ -245,20 +245,15 @@ pub fn render(p_original: &Peripheral, index: &Index, config: &Config) -> Result /// An enum describing the derivation status of an erc, which allows for disjoint arrays to be /// implicitly derived from a common type. -#[derive(Debug, PartialEq)] +#[derive(Default, Debug, PartialEq)] enum DeriveInfo { + #[default] Root, Explicit(RegisterPath), Implicit(RegisterPath), Cluster, // don't do anything different for clusters } -impl Default for DeriveInfo { - fn default() -> Self { - DeriveInfo::Root - } -} - impl fmt::Display for DeriveInfo { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{self:?}") diff --git a/src/generate/register.rs b/src/generate/register.rs index fc56fb25..82be12ec 100644 --- a/src/generate/register.rs +++ b/src/generate/register.rs @@ -8,6 +8,7 @@ use proc_macro2::{Ident, Punct, Spacing, Span, TokenStream}; use quote::{quote, ToTokens}; use std::borrow::Cow; use std::collections::HashSet; +use std::fmt::Write; use svd_parser::expand::{ derive_enumerated_values, derive_field, BlockPath, EnumPath, FieldPath, Index, RegisterPath, }; @@ -80,8 +81,24 @@ pub fn render( } else { return Err(anyhow!("Incorrect access of register {}", register.name)); }; - let alias_doc = - format!("{name} ({accs}) register accessor: an alias for `Reg<{regspec_ident}>`"); + + let mut alias_doc = format!( + "{name} ({accs}) register accessor: {description}\n\n{}", + api_docs( + access.can_read(), + access.can_write(), + register.properties.reset_value.is_some(), + &name_snake_case, + false, + register.read_action, + )? + ); + if name_snake_case != "cfg" { + alias_doc += format!( + "\n\nFor information about available fields see [`{name_snake_case}`] module" + ) + .as_str(); + } let mut out = TokenStream::new(); out.extend(quote! { #[doc = #alias_doc] @@ -106,6 +123,68 @@ pub fn render( } } +fn api_docs( + can_read: bool, + can_write: bool, + can_reset: bool, + module: &Ident, + inmodule: bool, + read_action: Option, +) -> Result { + fn method(s: &str) -> String { + format!("[`{s}`](crate::generic::Reg::{s})") + } + + let mut doc = String::new(); + + if can_read { + write!( + doc, + "You can {} this register and get [`{module}::R`]{}. ", + method("read"), + if inmodule { "(R)" } else { "" }, + )?; + + if let Some(action) = read_action { + doc.push_str("WARN: "); + doc.push_str(match action { + ReadAction::Clear => "The register is **cleared** (set to zero) following a read operation.", + ReadAction::Set => "The register is **set** (set to ones) following a read operation.", + ReadAction::Modify => "The register is **modified** in some way after a read operation.", + ReadAction::ModifyExternal => "One or more dependent resources other than the current register are immediately affected by a read operation.", + }); + } + doc.push(' '); + } + + if can_write { + let mut methods = Vec::new(); + if can_reset { + methods.push("reset"); + methods.push("write"); + } + methods.push("write_with_zero"); + write!( + doc, + "You can {} this register using [`{module}::W`]{}. ", + methods + .iter() + .map(|m| method(m)) + .collect::>() + .join(", "), + if inmodule { "(W)" } else { "" }, + )?; + } + + if can_read && can_write { + write!(doc, "You can also {} this register. ", method("modify"),)?; + } + + doc.push_str("See [API](https://docs.rs/svd2rust/#read--modify--write-api)."); + + Ok(doc) +} + pub fn render_register_mod( register: &Register, access: Access, @@ -138,7 +217,6 @@ pub fn render_register_mod( ); let mut mod_items = TokenStream::new(); - let mut methods = vec![]; let can_read = access.can_read(); let can_write = access.can_write(); @@ -150,7 +228,6 @@ pub fn render_register_mod( #[doc = #desc] pub type R = crate::R<#regspec_ident>; }); - methods.push("read"); } if can_write { @@ -159,15 +236,6 @@ pub fn render_register_mod( #[doc = #desc] pub type W = crate::W<#regspec_ident>; }); - methods.push("write_with_zero"); - if can_reset { - methods.push("reset"); - methods.push("write"); - } - } - - if can_read && can_write { - methods.push("modify"); } let mut r_impl_items = TokenStream::new(); @@ -310,29 +378,17 @@ pub fn render_register_mod( close.to_tokens(&mut mod_items); } - let methods = methods - .iter() - .map(|s| format!("[`{s}`](crate::generic::Reg::{s})")) - .collect::>(); - let mut doc = format!("{description}\n\nThis register you can {}. See [API](https://docs.rs/svd2rust/#read--modify--write-api).", methods.join(", ")); - - if name_snake_case != "cfg" { - doc += format!( - "\n\nFor information about available fields see [{name_snake_case}](index.html) module" - ) - .as_str(); - } - - if can_read { - if let Some(action) = register.read_action { - doc += match action { - ReadAction::Clear => "\n\nThe register is **cleared** (set to zero) following a read operation.", - ReadAction::Set => "\n\nThe register is **set** (set to ones) following a read operation.", - ReadAction::Modify => "\n\nThe register is **modified** in some way after a read operation.", - ReadAction::ModifyExternal => "\n\nOne or more dependent resources other than the current register are immediately affected by a read operation.", - }; - } - } + let doc = format!( + "{description}\n\n{}", + api_docs( + can_read, + can_write, + can_reset, + &name_snake_case, + true, + register.read_action, + )? + ); mod_items.extend(quote! { #[doc = #doc] @@ -344,7 +400,7 @@ pub fn render_register_mod( }); if can_read { - let doc = format!("`read()` method returns [{name_snake_case}::R](R) reader structure",); + let doc = format!("`read()` method returns [`{name_snake_case}::R`](R) reader structure",); mod_items.extend(quote! { #[doc = #doc] impl crate::Readable for #regspec_ident {} @@ -352,7 +408,7 @@ pub fn render_register_mod( } if can_write { let doc = - format!("`write(|w| ..)` method takes [{name_snake_case}::W](W) writer structure",); + format!("`write(|w| ..)` method takes [`{name_snake_case}::W`](W) writer structure",); let zero_to_modify_fields_bitmap = util::hex(zero_to_modify_fields_bitmap); let one_to_modify_fields_bitmap = util::hex(one_to_modify_fields_bitmap);