diff --git a/CHANGELOG.md b/CHANGELOG.md index a145fbd5..acea4d55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/). - Add `svd::Device` validation after parsing by `serde` - Add `skip-crate-attributes` config flag - Better display parsing errors +- Add an `AVR` target which includes generic code to access configuration change protected registers in a more convenient way ## [v0.31.2] - 2023-11-29 diff --git a/src/config.rs b/src/config.rs index 7656bf43..a2083193 100644 --- a/src/config.rs +++ b/src/config.rs @@ -46,6 +46,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, } @@ -58,6 +60,7 @@ impl std::fmt::Display for Target { Target::RISCV => "riscv", Target::XtensaLX => "xtensa-lx", Target::Mips => "mips", + Target::Avr => "avr", Target::None => "none", }) } @@ -71,6 +74,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 4683e2cd..50a1c3f0 100644 --- a/src/generate/device.rs +++ b/src/generate/device.rs @@ -142,6 +142,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 c54e1d6b..34df2253 100644 --- a/src/generate/interrupt.rs +++ b/src/generate/interrupt.rs @@ -251,6 +251,7 @@ pub fn render( }); } Target::Mips => {} + Target::Avr => {} Target::None => {} } @@ -364,6 +365,7 @@ pub fn render( && target != Target::Msp430 && target != Target::XtensaLX && target != Target::Mips + && target != Target::Avr { mod_items.extend(quote! { #[cfg(feature = "rt")]