diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bfde64b9..99ec2303 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,6 +1,6 @@ on: push: - branches: master + branches: [master] pull_request: merge_group: @@ -83,7 +83,11 @@ jobs: - { rust: stable, vendor: Spansion, options: "--atomics" } - { rust: stable, vendor: STMicro, options: "" } - { rust: stable, vendor: STMicro, options: "--atomics" } - - { rust: stable, vendor: STM32-patched, options: "--strict -f enum_value::p: --max-cluster-size --atomics --atomics-feature atomics --impl-debug --impl-defmt defmt" } + - { + rust: stable, + vendor: STM32-patched, + options: "--strict -f enum_value::p: --max-cluster-size --atomics --atomics-feature atomics --impl-debug --impl-defmt defmt", + } - { rust: stable, vendor: Toshiba, options: all } - { rust: stable, vendor: Toshiba, options: "" } # Test MSRV @@ -92,8 +96,16 @@ jobs: - { rust: nightly, vendor: MSP430, options: "--atomics" } - { rust: nightly, vendor: MSP430, options: "" } # Workaround for _1token0 - - { rust: nightly-2024-09-25, vendor: Espressif, options: "--atomics --ident-formats-theme legacy" } - - { rust: nightly-2024-09-25, vendor: Espressif, options: "--ident-format register:::Reg" } + - { + rust: nightly-2024-09-25, + vendor: Espressif, + options: "--atomics --ident-formats-theme legacy", + } + - { + rust: nightly-2024-09-25, + vendor: Espressif, + options: "--ident-format register:::Reg", + } steps: - uses: actions/checkout@v4 diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ee8ba46..4985ebc6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/). ## [Unreleased] +- Use `ConstZero::ZERO` instead of `Default::default()` to force const - Force using rust edition 2021 in CI ## [v0.35.0] - 2024-11-12 diff --git a/ci/script.sh b/ci/script.sh index 6524bb60..1db33f13 100755 --- a/ci/script.sh +++ b/ci/script.sh @@ -43,6 +43,7 @@ main() { echo 'cortex-m = "0.7.7"' >> $td/Cargo.toml echo 'cortex-m-rt = "0.7.3"' >> $td/Cargo.toml echo 'vcell = "0.1.3"' >> $td/Cargo.toml + echo 'num-traits = { version = "0.2.19", default-features = false }' >> $td/Cargo.toml if [[ "$options" == *"--atomics"* ]]; then echo 'portable-atomic = { version = "1.4", default-features = false }' >> $td/Cargo.toml fi diff --git a/ci/svd2rust-regress/src/svd_test.rs b/ci/svd2rust-regress/src/svd_test.rs index 30033dbd..f2ce70db 100644 --- a/ci/svd2rust-regress/src/svd_test.rs +++ b/ci/svd2rust-regress/src/svd_test.rs @@ -11,7 +11,11 @@ use std::{ path::Path, }; -const CRATES_ALL: &[&str] = &["critical-section = \"1.0\"", "vcell = \"0.1.2\""]; +const CRATES_ALL: &[&str] = &[ + "critical-section = \"1.0\"", + "vcell = \"0.1.2\"", + "num-traits = { version = \"0.2.19\", default-features = false }", +]; const CRATES_MSP430: &[&str] = &["msp430 = \"0.4.0\"", "msp430-rt = \"0.4.0\""]; const CRATES_ATOMICS: &[&str] = &["portable-atomic = { version = \"0.3.16\", default-features = false }"]; diff --git a/src/generate/generic.rs b/src/generate/generic.rs index 706b7e12..e509300a 100644 --- a/src/generate/generic.rs +++ b/src/generate/generic.rs @@ -1,9 +1,11 @@ use core::marker; +use num_traits::{ConstOne, ConstZero}; /// Raw register type (`u8`, `u16`, `u32`, ...) pub trait RawReg: Copy - + Default + + ConstOne + + ConstZero + From + core::ops::BitOr + core::ops::BitAnd @@ -14,8 +16,6 @@ pub trait RawReg: { /// Mask for bits of width `WI` fn mask() -> Self; - /// Mask for bits of width 1 - fn one() -> Self; } macro_rules! raw_reg { @@ -25,10 +25,6 @@ macro_rules! raw_reg { fn mask() -> Self { $mask::() } - #[inline(always)] - fn one() -> Self { - 1 - } } const fn $mask() -> $U { <$U>::MAX >> ($size - WI) @@ -74,10 +70,10 @@ pub trait Writable: RegisterSpec { type Safety; /// Specifies the register bits that are not changed if you pass `1` and are changed if you pass `0` - const ZERO_TO_MODIFY_FIELDS_BITMAP: Self::Ux; + const ZERO_TO_MODIFY_FIELDS_BITMAP: Self::Ux = Self::Ux::ZERO; /// Specifies the register bits that are not changed if you pass `0` and are changed if you pass `1` - const ONE_TO_MODIFY_FIELDS_BITMAP: Self::Ux; + const ONE_TO_MODIFY_FIELDS_BITMAP: Self::Ux = Self::Ux::ZERO; } /// Reset value of the register. @@ -86,7 +82,7 @@ pub trait Writable: RegisterSpec { /// register by using the `reset` method. pub trait Resettable: RegisterSpec { /// Reset value of the register. - const RESET_VALUE: Self::Ux; + const RESET_VALUE: Self::Ux = Self::Ux::ZERO; /// Reset value of the register. #[inline(always)] @@ -247,7 +243,10 @@ impl W { self } } -impl W where REG: Writable { +impl W +where + REG: Writable, +{ /// Writes raw bits to the register. #[inline(always)] pub fn set(&mut self, bits: REG::Ux) -> &mut Self { @@ -335,7 +334,8 @@ pub struct RangeFrom; pub struct RangeTo; /// Write field Proxy -pub type FieldWriter<'a, REG, const WI: u8, FI = u8, Safety = Unsafe> = raw::FieldWriter<'a, REG, WI, FI, Safety>; +pub type FieldWriter<'a, REG, const WI: u8, FI = u8, Safety = Unsafe> = + raw::FieldWriter<'a, REG, WI, FI, Safety>; impl<'a, REG, const WI: u8, FI, Safety> FieldWriter<'a, REG, WI, FI, Safety> where @@ -390,7 +390,8 @@ where } } -impl<'a, REG, const WI: u8, FI, const MIN: u64, const MAX: u64> FieldWriter<'a, REG, WI, FI, Range> +impl<'a, REG, const WI: u8, FI, const MIN: u64, const MAX: u64> + FieldWriter<'a, REG, WI, FI, Range> where REG: Writable + RegisterSpec, FI: FieldSpec, @@ -478,7 +479,7 @@ macro_rules! bit_proxy { pub const fn width(&self) -> u8 { Self::WIDTH } - + /// Field offset #[inline(always)] pub const fn offset(&self) -> u8 { @@ -488,8 +489,8 @@ macro_rules! bit_proxy { /// Writes bit to the field #[inline(always)] pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits &= !(REG::Ux::one() << self.o); - self.w.bits |= (REG::Ux::from(value) & REG::Ux::one()) << self.o; + self.w.bits &= !(REG::Ux::ONE << self.o); + self.w.bits |= (REG::Ux::from(value) & REG::Ux::ONE) << self.o; self.w } /// Writes `variant` to the field @@ -517,13 +518,13 @@ where /// Sets the field bit #[inline(always)] pub fn set_bit(self) -> &'a mut W { - self.w.bits |= REG::Ux::one() << self.o; + self.w.bits |= REG::Ux::ONE << self.o; self.w } /// Clears the field bit #[inline(always)] pub fn clear_bit(self) -> &'a mut W { - self.w.bits &= !(REG::Ux::one() << self.o); + self.w.bits &= !(REG::Ux::ONE << self.o); self.w } } @@ -536,7 +537,7 @@ where /// Sets the field bit #[inline(always)] pub fn set_bit(self) -> &'a mut W { - self.w.bits |= REG::Ux::one() << self.o; + self.w.bits |= REG::Ux::ONE << self.o; self.w } } @@ -549,7 +550,7 @@ where /// Clears the field bit #[inline(always)] pub fn clear_bit(self) -> &'a mut W { - self.w.bits &= !(REG::Ux::one() << self.o); + self.w.bits &= !(REG::Ux::ONE << self.o); self.w } } @@ -562,7 +563,7 @@ where ///Clears the field bit by passing one #[inline(always)] pub fn clear_bit_by_one(self) -> &'a mut W { - self.w.bits |= REG::Ux::one() << self.o; + self.w.bits |= REG::Ux::ONE << self.o; self.w } } @@ -575,7 +576,7 @@ where ///Sets the field bit by passing zero #[inline(always)] pub fn set_bit_by_zero(self) -> &'a mut W { - self.w.bits &= !(REG::Ux::one() << self.o); + self.w.bits &= !(REG::Ux::ONE << self.o); self.w } } @@ -588,7 +589,7 @@ where ///Toggle the field bit by passing one #[inline(always)] pub fn toggle_bit(self) -> &'a mut W { - self.w.bits |= REG::Ux::one() << self.o; + self.w.bits |= REG::Ux::ONE << self.o; self.w } } @@ -601,7 +602,7 @@ where ///Toggle the field bit by passing zero #[inline(always)] pub fn toggle_bit(self) -> &'a mut W { - self.w.bits &= !(REG::Ux::one() << self.o); + self.w.bits &= !(REG::Ux::ONE << self.o); self.w } } diff --git a/src/generate/generic_atomic.rs b/src/generate/generic_atomic.rs index 54c491c3..55250961 100644 --- a/src/generate/generic_atomic.rs +++ b/src/generate/generic_atomic.rs @@ -39,7 +39,7 @@ mod atomic { impl Reg where - REG::Ux: AtomicOperations + REG::Ux: AtomicOperations, { /// Set high every bit in the register that was set in the write proxy. Leave other bits /// untouched. The write is done in a single atomic instruction. @@ -53,7 +53,7 @@ mod atomic { F: FnOnce(&mut W) -> &mut W, { let bits = f(&mut W { - bits: Default::default(), + bits: REG::Ux::ZERO, _reg: marker::PhantomData, }) .bits; @@ -72,7 +72,7 @@ mod atomic { F: FnOnce(&mut W) -> &mut W, { let bits = f(&mut W { - bits: !REG::Ux::default(), + bits: !REG::Ux::ZERO, _reg: marker::PhantomData, }) .bits; @@ -91,7 +91,7 @@ mod atomic { F: FnOnce(&mut W) -> &mut W, { let bits = f(&mut W { - bits: Default::default(), + bits: REG::Ux::ZERO, _reg: marker::PhantomData, }) .bits; diff --git a/src/generate/generic_reg_vcell.rs b/src/generate/generic_reg_vcell.rs index b0ca0d5e..9e436334 100644 --- a/src/generate/generic_reg_vcell.rs +++ b/src/generate/generic_reg_vcell.rs @@ -148,7 +148,7 @@ impl Reg { F: FnOnce(&mut W) -> &mut W, { let value = f(&mut W { - bits: REG::Ux::default(), + bits: REG::Ux::ZERO, _reg: marker::PhantomData, }) .bits; @@ -169,7 +169,7 @@ impl Reg { F: FnOnce(&mut W) -> T, { let mut writer = W { - bits: REG::Ux::default(), + bits: REG::Ux::ZERO, _reg: marker::PhantomData, }; diff --git a/src/generate/register.rs b/src/generate/register.rs index 92322ebe..fcce8624 100644 --- a/src/generate/register.rs +++ b/src/generate/register.rs @@ -413,24 +413,31 @@ pub fn render_register_mod( let doc = format!("`write(|w| ..)` method takes [`{mod_ty}::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); + let zero_to_modify_fields_bitmap = util::hex_nonzero(zero_to_modify_fields_bitmap) + .map(|bm| quote!(const ZERO_TO_MODIFY_FIELDS_BITMAP: #rty = #bm;)); + let one_to_modify_fields_bitmap = util::hex_nonzero(one_to_modify_fields_bitmap) + .map(|bm| quote!(const ONE_TO_MODIFY_FIELDS_BITMAP: #rty = #bm;)); mod_items.extend(quote! { #[doc = #doc] impl crate::Writable for #regspec_ty { type Safety = crate::#safe_ty; - const ZERO_TO_MODIFY_FIELDS_BITMAP: #rty = #zero_to_modify_fields_bitmap; - const ONE_TO_MODIFY_FIELDS_BITMAP: #rty = #one_to_modify_fields_bitmap; + #zero_to_modify_fields_bitmap + #one_to_modify_fields_bitmap } }); } - if let Some(rv) = properties.reset_value.map(util::hex) { - let doc = format!("`reset()` method sets {} to value {rv}", register.name); + if let Some(rv) = properties.reset_value.map(util::hex_nonzero) { + let doc = if let Some(rv) = &rv { + format!("`reset()` method sets {} to value {rv}", register.name) + } else { + format!("`reset()` method sets {} to value 0", register.name) + }; + let rv = rv.map(|rv| quote!(const RESET_VALUE: #rty = #rv;)); mod_items.extend(quote! { #[doc = #doc] impl crate::Resettable for #regspec_ty { - const RESET_VALUE: #rty = #rv; + #rv } }); } diff --git a/src/lib.rs b/src/lib.rs index b5d5c4ab..924c6ba9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -62,6 +62,7 @@ //! - [`cortex-m`](https://crates.io/crates/cortex-m) >=v0.7.6 //! - [`cortex-m-rt`](https://crates.io/crates/cortex-m-rt) >=v0.6.13 //! - [`vcell`](https://crates.io/crates/vcell) >=v0.1.2 +//! - [`num-traits`](https://crates.io/crates/const-default) >=v0.2.18 //! //! Furthermore, the "device" feature of `cortex-m-rt` must be enabled when the `rt` feature //! is enabled. The `Cargo.toml` of the device crate will look like this: @@ -126,6 +127,7 @@ //! - [`msp430`](https://crates.io/crates/msp430) v0.4.x //! - [`msp430-rt`](https://crates.io/crates/msp430-rt) v0.4.x //! - [`vcell`](https://crates.io/crates/vcell) v0.1.x +//! - [`num-traits`](https://crates.io/crates/const-default) v0.2.x //! //! The "device" feature of `msp430-rt` must be enabled when the `rt` feature is //! enabled. The `Cargo.toml` of the device crate will look like this: @@ -136,6 +138,7 @@ //! msp430 = "0.4.0" //! msp430-rt = { version = "0.4.0", optional = true } //! vcell = "0.1.0" +//! num-traits = { version = "0.2.19", default-features = false } //! //! [features] //! rt = ["msp430-rt/device"] @@ -153,6 +156,7 @@ //! - [`riscv-peripheral`](https://crates.io/crates/riscv-peripheral) v0.2.x (if target is RISC-V and has standard peripherals) //! - [`riscv-rt`](https://crates.io/crates/riscv-rt) v0.13.x (if target is RISC-V) //! - [`vcell`](https://crates.io/crates/vcell) v0.1.x +//! - [`num-traits`](https://crates.io/crates/const-default) v0.2.x //! //! The `*-rt` dependencies must be optional only enabled when the `rt` feature is enabled. //! If target is RISC-V and supports vectored mode, you must include a feature `v-trap` to activate `riscv-rt/v-trap`. @@ -165,6 +169,7 @@ //! riscv-peripheral = "0.2.0" //! riscv-rt = { version = "0.13.0", optional = true } //! vcell = "0.1.0" +//! num-traits = { version = "0.2.19", default-features = false } //! //! [features] //! rt = ["riscv-rt"] diff --git a/src/util.rs b/src/util.rs index 5c56f3c3..1a30ea08 100644 --- a/src/util.rs +++ b/src/util.rs @@ -255,6 +255,11 @@ pub fn hex(n: u64) -> LitInt { ) } +/// Turns non-zero `n` into an unsuffixed separated hex token +pub fn hex_nonzero(n: u64) -> Option { + (n != 0).then(|| hex(n)) +} + /// Turns `n` into an unsuffixed token pub fn unsuffixed(n: impl Into) -> LitInt { LitInt::new(&n.into().to_string(), Span::call_site())