From 5b3d5f57aff724450a7d704855c994e946d175d3 Mon Sep 17 00:00:00 2001 From: Andreas Galauner Date: Sun, 10 Dec 2023 07:03:51 +0100 Subject: [PATCH 1/2] Add a new generic file to be included which provide register access methods for AVR registers which are protected by the configuration change protection (CCP) --- src/config.rs | 4 + src/generate/device.rs | 7 ++ src/generate/generic_avr_ccp.rs | 127 ++++++++++++++++++++++++++++++++ src/generate/interrupt.rs | 2 + 4 files changed, 140 insertions(+) create mode 100644 src/generate/generic_avr_ccp.rs diff --git a/src/config.rs b/src/config.rs index e7b224fc..ef7e8b9e 100644 --- a/src/config.rs +++ b/src/config.rs @@ -79,6 +79,8 @@ pub enum Target { XtensaLX, #[cfg_attr(feature = "serde", serde(rename = "mips"))] Mips, + #[cfg_attr(feature = "serde", serde(rename = "avr"))] + Avr, #[cfg_attr(feature = "serde", serde(rename = "none"))] None, } @@ -91,6 +93,7 @@ impl std::fmt::Display for Target { Target::RISCV => "riscv", Target::XtensaLX => "xtensa-lx", Target::Mips => "mips", + Target::Avr => "avr", Target::None => "none", }) } @@ -104,6 +107,7 @@ impl Target { "riscv" => Target::RISCV, "xtensa-lx" => Target::XtensaLX, "mips" => Target::Mips, + "avr" => Target::Avr, "none" => Target::None, _ => bail!("unknown target {}", s), }) diff --git a/src/generate/device.rs b/src/generate/device.rs index e21d249d..a4e4c3f0 100644 --- a/src/generate/device.rs +++ b/src/generate/device.rs @@ -139,6 +139,7 @@ pub fn render(d: &Device, config: &Config, device_x: &mut String) -> Result Result Result +where + REG: Writable + Protected +{ + /// Write to a CCP protected register by unlocking it first. + /// + /// Refer to [`Reg::write`] for usage. + fn write_protected(&self, f: F) + where + F: FnOnce(&mut W) -> &mut W; +} + +impl ProtectedWritable for Reg +where + REG: RegisterSpec + Writable + Resettable + Protected +{ + /// Unlocks and then writes bits to a `Writable` register. + /// + /// Refer to [`Reg::write`] for usage. + #[inline(always)] + fn write_protected(&self, f: F) + where + F: FnOnce(&mut W) -> &mut W + { + let val = f(&mut W::::from(W { + bits: REG::RESET_VALUE & !REG::ONE_TO_MODIFY_FIELDS_BITMAP + | REG::ZERO_TO_MODIFY_FIELDS_BITMAP, + _reg: marker::PhantomData, + })).bits; + + unsafe { + core::arch::asm!( + // Write the CCP register with the desired magic + "ldi {magicreg}, {magic}", + "out {ccpreg}, {magicreg}", + + // Then immediately write the protected register + "st X, {perval}", + + magic = const REG::MAGIC, + ccpreg = const unsafe { core::mem::transmute::<_, i16>(REG::CcpReg::PTR) as i32 }, + + in("X") self.register.as_ptr(), + perval = in(reg) val, + + magicreg = out (reg) _ // mark the magicreg as clobbered + ); + } + } +} + +impl + Readable + Writable + Protected> Reg { + /// Modifies the contents of a protected register by reading and then + /// unlocking and writing it. + /// + /// Refer to [`Reg::modify`] for usage. + #[inline(always)] + pub fn modify_protected(&self, f: F) + where + for<'w> F: FnOnce(&R, &'w mut W) -> &'w mut W, + { + let bits = self.register.get(); + let val = f( + &R::::from(R { + bits, + _reg: marker::PhantomData, + }), + &mut W::::from(W { + bits: bits & !REG::ONE_TO_MODIFY_FIELDS_BITMAP + | REG::ZERO_TO_MODIFY_FIELDS_BITMAP, + _reg: marker::PhantomData, + }), + ) + .bits; + + unsafe { + core::arch::asm!( + // Write the CCP register with the desired magic + "ldi {magicreg}, {magic}", + "out {ccpreg}, {magicreg}", + + // Then immediately write the protected register + "st X, {perval}", + + magic = const REG::MAGIC, + ccpreg = const unsafe { core::mem::transmute::<_, i16>(REG::CcpReg::PTR) as i32 }, + + in("X") self.register.as_ptr(), + perval = in(reg) val, + + magicreg = out (reg) _ // mark the magicreg as clobbered + ); + } + } +} diff --git a/src/generate/interrupt.rs b/src/generate/interrupt.rs index 1e9420fb..b0381e93 100644 --- a/src/generate/interrupt.rs +++ b/src/generate/interrupt.rs @@ -269,6 +269,7 @@ pub fn render( }); } Target::Mips => {} + Target::Avr => {} Target::None => {} } @@ -377,6 +378,7 @@ pub fn render( && target != Target::Msp430 && target != Target::XtensaLX && target != Target::Mips + && target != Target::Avr { mod_items.extend(quote! { #[cfg(feature = "rt")] From d8be92cd783468cf7d5813d88d91abede555dc50 Mon Sep 17 00:00:00 2001 From: Andreas Galauner Date: Sun, 10 Dec 2023 07:33:10 +0100 Subject: [PATCH 2/2] Add AVR CCP feature in Changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8dc1d6f1..4136faa0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/). - Update `irx-config` - Fix register array derive regression - Sanitize `gen` keyword (new in Rust 2024 edition) +- Add an `AVR` target which includes generic code to access configuration change protected registers in a more convenient way ## [v0.36.0] - 2025-03-09