Skip to content

Commit 5b3d5f5

Browse files
committed
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)
1 parent 87c2fc4 commit 5b3d5f5

File tree

4 files changed

+140
-0
lines changed

4 files changed

+140
-0
lines changed

src/config.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ pub enum Target {
7979
XtensaLX,
8080
#[cfg_attr(feature = "serde", serde(rename = "mips"))]
8181
Mips,
82+
#[cfg_attr(feature = "serde", serde(rename = "avr"))]
83+
Avr,
8284
#[cfg_attr(feature = "serde", serde(rename = "none"))]
8385
None,
8486
}
@@ -91,6 +93,7 @@ impl std::fmt::Display for Target {
9193
Target::RISCV => "riscv",
9294
Target::XtensaLX => "xtensa-lx",
9395
Target::Mips => "mips",
96+
Target::Avr => "avr",
9497
Target::None => "none",
9598
})
9699
}
@@ -104,6 +107,7 @@ impl Target {
104107
"riscv" => Target::RISCV,
105108
"xtensa-lx" => Target::XtensaLX,
106109
"mips" => Target::Mips,
110+
"avr" => Target::Avr,
107111
"none" => Target::None,
108112
_ => bail!("unknown target {}", s),
109113
})

src/generate/device.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ pub fn render(d: &Device, config: &Config, device_x: &mut String) -> Result<Toke
139139
let generic_file = include_str!("generic.rs");
140140
let generic_reg_file = include_str!("generic_reg_vcell.rs");
141141
let generic_atomic_file = include_str!("generic_atomic.rs");
142+
let avr_ccp_file = include_str!("generic_avr_ccp.rs");
142143
if config.generic_mod {
143144
let mut file = File::create(
144145
config
@@ -155,6 +156,9 @@ pub fn render(d: &Device, config: &Config, device_x: &mut String) -> Result<Toke
155156
}
156157
writeln!(file, "\n{generic_atomic_file}")?;
157158
}
159+
if config.target == Target::Avr {
160+
writeln!(file, "\n{}", avr_ccp_file)?;
161+
}
158162

159163
if !config.make_mod {
160164
out.extend(quote! {
@@ -173,6 +177,9 @@ pub fn render(d: &Device, config: &Config, device_x: &mut String) -> Result<Toke
173177
}
174178
syn::parse_file(generic_atomic_file)?.to_tokens(&mut tokens);
175179
}
180+
if config.target == Target::Avr {
181+
syn::parse_file(avr_ccp_file)?.to_tokens(&mut tokens);
182+
}
176183

177184
out.extend(quote! {
178185
#[allow(unused_imports)]

src/generate/generic_avr_ccp.rs

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
/// Trait implemented by registers that can be used to unlock another
2+
/// configuration change protected register.
3+
///
4+
/// A type reference to an unlock register needs to be defined in every
5+
/// implementation of a [`Protected`]
6+
pub trait UnlockRegister {
7+
/// A raw pointer to the location of the CCP register in data space
8+
const PTR: *mut u8;
9+
}
10+
11+
/// Trait to mark a register as configuration change protected on xmega based
12+
/// AVR cores.
13+
///
14+
/// To write into a configuration change protected register, the CPU first has
15+
/// to issue a write a defined magic value to a register called `CCP` in the
16+
/// `CPU` block of the core. After this write access has been performed, the
17+
/// protected register has to be written within the next four instruction for
18+
/// the write to take effect.
19+
pub trait Protected {
20+
/// The CCP [`UnlockRegister`] that needs to be written with the
21+
/// [`Self::MAGIC`] value to unlock writes to the protected register.
22+
type CcpReg: UnlockRegister;
23+
24+
/// The magic value that needs to be written into the configuration change
25+
/// protection register [`Self::CcpReg`] to unlock writes to the protected
26+
/// register
27+
const MAGIC: u8;
28+
}
29+
30+
/// Trait implemented by [`Writable`] and [`Protected`] registers which
31+
/// allows writing to the protected register by first writing a magic value to
32+
/// the CCP register.
33+
pub trait ProtectedWritable<REG>
34+
where
35+
REG: Writable + Protected
36+
{
37+
/// Write to a CCP protected register by unlocking it first.
38+
///
39+
/// Refer to [`Reg::write`] for usage.
40+
fn write_protected<F>(&self, f: F)
41+
where
42+
F: FnOnce(&mut W<REG>) -> &mut W<REG>;
43+
}
44+
45+
impl<REG> ProtectedWritable<REG> for Reg<REG>
46+
where
47+
REG: RegisterSpec<Ux = u8> + Writable + Resettable + Protected
48+
{
49+
/// Unlocks and then writes bits to a `Writable` register.
50+
///
51+
/// Refer to [`Reg::write`] for usage.
52+
#[inline(always)]
53+
fn write_protected<F>(&self, f: F)
54+
where
55+
F: FnOnce(&mut W<REG>) -> &mut W<REG>
56+
{
57+
let val = f(&mut W::<REG>::from(W {
58+
bits: REG::RESET_VALUE & !REG::ONE_TO_MODIFY_FIELDS_BITMAP
59+
| REG::ZERO_TO_MODIFY_FIELDS_BITMAP,
60+
_reg: marker::PhantomData,
61+
})).bits;
62+
63+
unsafe {
64+
core::arch::asm!(
65+
// Write the CCP register with the desired magic
66+
"ldi {magicreg}, {magic}",
67+
"out {ccpreg}, {magicreg}",
68+
69+
// Then immediately write the protected register
70+
"st X, {perval}",
71+
72+
magic = const REG::MAGIC,
73+
ccpreg = const unsafe { core::mem::transmute::<_, i16>(REG::CcpReg::PTR) as i32 },
74+
75+
in("X") self.register.as_ptr(),
76+
perval = in(reg) val,
77+
78+
magicreg = out (reg) _ // mark the magicreg as clobbered
79+
);
80+
}
81+
}
82+
}
83+
84+
impl<REG: RegisterSpec<Ux = u8> + Readable + Writable + Protected> Reg<REG> {
85+
/// Modifies the contents of a protected register by reading and then
86+
/// unlocking and writing it.
87+
///
88+
/// Refer to [`Reg::modify`] for usage.
89+
#[inline(always)]
90+
pub fn modify_protected<F>(&self, f: F)
91+
where
92+
for<'w> F: FnOnce(&R<REG>, &'w mut W<REG>) -> &'w mut W<REG>,
93+
{
94+
let bits = self.register.get();
95+
let val = f(
96+
&R::<REG>::from(R {
97+
bits,
98+
_reg: marker::PhantomData,
99+
}),
100+
&mut W::<REG>::from(W {
101+
bits: bits & !REG::ONE_TO_MODIFY_FIELDS_BITMAP
102+
| REG::ZERO_TO_MODIFY_FIELDS_BITMAP,
103+
_reg: marker::PhantomData,
104+
}),
105+
)
106+
.bits;
107+
108+
unsafe {
109+
core::arch::asm!(
110+
// Write the CCP register with the desired magic
111+
"ldi {magicreg}, {magic}",
112+
"out {ccpreg}, {magicreg}",
113+
114+
// Then immediately write the protected register
115+
"st X, {perval}",
116+
117+
magic = const REG::MAGIC,
118+
ccpreg = const unsafe { core::mem::transmute::<_, i16>(REG::CcpReg::PTR) as i32 },
119+
120+
in("X") self.register.as_ptr(),
121+
perval = in(reg) val,
122+
123+
magicreg = out (reg) _ // mark the magicreg as clobbered
124+
);
125+
}
126+
}
127+
}

src/generate/interrupt.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,7 @@ pub fn render(
269269
});
270270
}
271271
Target::Mips => {}
272+
Target::Avr => {}
272273
Target::None => {}
273274
}
274275

@@ -377,6 +378,7 @@ pub fn render(
377378
&& target != Target::Msp430
378379
&& target != Target::XtensaLX
379380
&& target != Target::Mips
381+
&& target != Target::Avr
380382
{
381383
mod_items.extend(quote! {
382384
#[cfg(feature = "rt")]

0 commit comments

Comments
 (0)