Skip to content

Commit 6b21a70

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 76cd523 commit 6b21a70

File tree

4 files changed

+140
-0
lines changed

4 files changed

+140
-0
lines changed

Diff for: src/config.rs

+4
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ pub enum Target {
4646
XtensaLX,
4747
#[cfg_attr(feature = "serde", serde(rename = "mips"))]
4848
Mips,
49+
#[cfg_attr(feature = "serde", serde(rename = "avr"))]
50+
Avr,
4951
#[cfg_attr(feature = "serde", serde(rename = "none"))]
5052
None,
5153
}
@@ -58,6 +60,7 @@ impl std::fmt::Display for Target {
5860
Target::RISCV => "riscv",
5961
Target::XtensaLX => "xtensa-lx",
6062
Target::Mips => "mips",
63+
Target::Avr => "avr",
6164
Target::None => "none",
6265
})
6366
}
@@ -71,6 +74,7 @@ impl Target {
7174
"riscv" => Target::RISCV,
7275
"xtensa-lx" => Target::XtensaLX,
7376
"mips" => Target::Mips,
77+
"avr" => Target::Avr,
7478
"none" => Target::None,
7579
_ => bail!("unknown target {}", s),
7680
})

Diff for: src/generate/device.rs

+7
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ pub fn render(d: &Device, config: &Config, device_x: &mut String) -> Result<Toke
142142

143143
let generic_file = include_str!("generic.rs");
144144
let generic_atomic_file = include_str!("generic_atomic.rs");
145+
let avr_ccp_file = include_str!("generic_avr_ccp.rs");
145146
if config.generic_mod {
146147
let mut file = File::create(
147148
config
@@ -157,6 +158,9 @@ pub fn render(d: &Device, config: &Config, device_x: &mut String) -> Result<Toke
157158
}
158159
writeln!(file, "\n{generic_atomic_file}")?;
159160
}
161+
if config.target == Target::Avr {
162+
writeln!(file, "\n{}", avr_ccp_file)?;
163+
}
160164

161165
if !config.make_mod {
162166
out.extend(quote! {
@@ -174,6 +178,9 @@ pub fn render(d: &Device, config: &Config, device_x: &mut String) -> Result<Toke
174178
}
175179
syn::parse_file(generic_atomic_file)?.to_tokens(&mut tokens);
176180
}
181+
if config.target == Target::Avr {
182+
syn::parse_file(avr_ccp_file)?.to_tokens(&mut tokens);
183+
}
177184

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

Diff for: src/generate/generic_avr_ccp.rs

+127
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+
}

Diff for: src/generate/interrupt.rs

+2
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,7 @@ pub fn render(
251251
});
252252
}
253253
Target::Mips => {}
254+
Target::Avr => {}
254255
Target::None => {}
255256
}
256257

@@ -364,6 +365,7 @@ pub fn render(
364365
&& target != Target::Msp430
365366
&& target != Target::XtensaLX
366367
&& target != Target::Mips
368+
&& target != Target::Avr
367369
{
368370
mod_items.extend(quote! {
369371
#[cfg(feature = "rt")]

0 commit comments

Comments
 (0)