Skip to content

Commit a02a5cf

Browse files
bors[bot]YuhanLiin
andauthored
Merge #520
520: Support for atomic bitwise operations in MSP430 PAC API r=burrbull a=YuhanLiin Rebased version of #407 with updated changelog. Co-authored-by: YuhanLiin <[email protected]> Co-authored-by: YuhanLiin <[email protected]>
2 parents f66f169 + e6ca27e commit a02a5cf

File tree

6 files changed

+132
-19
lines changed

6 files changed

+132
-19
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
99

1010
### Added
1111

12+
- MSP430 API for atomically changing register bits, gated behind the `--nightly` flag
13+
- New SVD test for `msp430fr2355`
14+
15+
### Added
16+
1217
- Option `-o`(`--output-path`) let you specify output directory path
1318

1419
### Changed

ci/svd2rust-regress/src/svd_test.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ use std::path::PathBuf;
66
use std::process::{Command, Output};
77

88
const CRATES_ALL: &[&str] = &["bare-metal = \"0.2.0\"", "vcell = \"0.1.2\""];
9-
const CRATES_MSP430: &[&str] = &["msp430 = \"0.2.2\""];
9+
const CRATES_MSP430: &[&str] = &["msp430 = \"0.2.2\"", "msp430-rt = \"0.2.0\""];
10+
const CRATES_MSP430_NIGHTLY: &[&str] = &["msp430-atomic = \"0.1.2\""];
1011
const CRATES_CORTEX_M: &[&str] = &["cortex-m = \"0.7.0\"", "cortex-m-rt = \"0.6.13\""];
1112
const CRATES_RISCV: &[&str] = &["riscv = \"0.5.0\"", "riscv-rt = \"0.6.0\""];
1213
const CRATES_XTENSALX6: &[&str] = &["xtensa-lx6-rt = \"0.2.0\"", "xtensa-lx6 = \"0.1.0\""];
@@ -134,6 +135,14 @@ pub fn test(
134135
Msp430 => CRATES_MSP430.iter(),
135136
XtensaLX => CRATES_XTENSALX6.iter(),
136137
})
138+
.chain(if nightly {
139+
match &t.arch {
140+
Msp430 => CRATES_MSP430_NIGHTLY.iter(),
141+
_ => [].iter(),
142+
}
143+
} else {
144+
[].iter()
145+
})
137146
.chain(PROFILE_ALL.iter())
138147
.chain(FEATURES_ALL.iter());
139148

ci/svd2rust-regress/src/tests.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4230,6 +4230,16 @@ pub const TESTS: &[&TestCase] = &[
42304230
should_pass: true,
42314231
run_when: Always,
42324232
},
4233+
&TestCase {
4234+
arch: Msp430,
4235+
mfgr: TexasInstruments,
4236+
chip: "msp430fr2355",
4237+
svd_url: Some(
4238+
"https://raw.githubusercontent.com/YuhanLiin/msp430fr2355/rt-up/msp430fr2355.svd",
4239+
),
4240+
should_pass: true,
4241+
run_when: Always,
4242+
},
42334243
&TestCase {
42344244
arch: XtensaLX,
42354245
mfgr: Espressif,

src/generate/device.rs

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -139,11 +139,13 @@ pub fn render(d: &Device, config: &Config, device_x: &mut String) -> Result<Toke
139139

140140
let generic_file = std::str::from_utf8(include_bytes!("generic.rs"))?;
141141
if config.generic_mod {
142-
writeln!(
143-
File::create(config.output_dir.join("generic.rs"))?,
144-
"{}",
145-
generic_file
146-
)?;
142+
let mut file = File::create(config.output_dir.join("generic.rs"))?;
143+
writeln!(file, "{}", generic_file)?;
144+
if config.target == Target::Msp430 && config.nightly {
145+
let msp430_atomic_file =
146+
std::str::from_utf8(include_bytes!("generic_msp430_atomic.rs"))?;
147+
writeln!(file, "\n{}", msp430_atomic_file)?;
148+
}
147149

148150
if !config.make_mod {
149151
out.extend(quote! {
@@ -156,14 +158,30 @@ pub fn render(d: &Device, config: &Config, device_x: &mut String) -> Result<Toke
156158
} else {
157159
let tokens = syn::parse_file(generic_file)?.into_token_stream();
158160

159-
out.extend(quote! {
160-
#[allow(unused_imports)]
161-
use generic::*;
162-
///Common register and bit access and modify traits
163-
pub mod generic {
164-
#tokens
165-
}
166-
});
161+
if config.target == Target::Msp430 && config.nightly {
162+
let msp430_atomic_file =
163+
std::str::from_utf8(include_bytes!("generic_msp430_atomic.rs"))?;
164+
let generic_msp430_atomic = syn::parse_file(msp430_atomic_file)?.into_token_stream();
165+
out.extend(quote! {
166+
#[allow(unused_imports)]
167+
use generic::*;
168+
///Common register and bit access and modify traits
169+
pub mod generic {
170+
#tokens
171+
172+
#generic_msp430_atomic
173+
}
174+
});
175+
} else {
176+
out.extend(quote! {
177+
#[allow(unused_imports)]
178+
use generic::*;
179+
///Common register and bit access and modify traits
180+
pub mod generic {
181+
#tokens
182+
}
183+
});
184+
}
167185
}
168186

169187
out.extend(interrupt::render(config.target, &d.peripherals, device_x)?);

src/generate/generic_msp430_atomic.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
use msp430_atomic::AtomicOperations;
2+
3+
impl<REG: Writable> Reg<REG>
4+
where
5+
Self: Readable + Writable,
6+
REG::Ux: AtomicOperations + Default + core::ops::Not<Output = REG::Ux>,
7+
{
8+
/// Set high every bit in the register that was set in the write proxy. Leave other bits
9+
/// untouched. The write is done in a single atomic instruction.
10+
#[inline(always)]
11+
pub unsafe fn set_bits<F>(&self, f: F)
12+
where
13+
F: FnOnce(&mut W<REG>) -> &mut W<REG>,
14+
{
15+
let bits = f(&mut W {
16+
bits: Default::default(),
17+
_reg: marker::PhantomData,
18+
})
19+
.bits;
20+
REG::Ux::atomic_or(self.register.as_ptr(), bits);
21+
}
22+
23+
/// Clear every bit in the register that was cleared in the write proxy. Leave other bits
24+
/// untouched. The write is done in a single atomic instruction.
25+
#[inline(always)]
26+
pub unsafe fn clear_bits<F>(&self, f: F)
27+
where
28+
F: FnOnce(&mut W<REG>) -> &mut W<REG>,
29+
{
30+
let bits = f(&mut W {
31+
bits: !REG::Ux::default(),
32+
_reg: marker::PhantomData,
33+
})
34+
.bits;
35+
REG::Ux::atomic_and(self.register.as_ptr(), bits);
36+
}
37+
38+
/// Toggle every bit in the register that was set in the write proxy. Leave other bits
39+
/// untouched. The write is done in a single atomic instruction.
40+
#[inline(always)]
41+
pub unsafe fn toggle_bits<F>(&self, f: F)
42+
where
43+
F: FnOnce(&mut W<REG>) -> &mut W<REG>,
44+
{
45+
let bits = f(&mut W {
46+
bits: Default::default(),
47+
_reg: marker::PhantomData,
48+
})
49+
.bits;
50+
REG::Ux::atomic_xor(self.register.as_ptr(), bits);
51+
}
52+
}

src/lib.rs

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -108,22 +108,25 @@
108108
//! $ cargo fmt
109109
//! ```
110110
//!
111-
//! The resulting crate must provide an opt-in "rt" feature and depend on these crates:
112-
//! `msp430` v0.2.x, `msp430-rt` v0.2.x and `vcell` v0.1.x. Furthermore
113-
//! the "device" feature of `msp430-rt` must be enabled when the "rt" feature is enabled. The
114-
//! `Cargo.toml` of the device crate will look like this:
111+
//! The resulting crate must provide opt-in "rt" feature and depend on these crates: `msp430`
112+
//! v0.2.x, `msp430-rt` v0.2.x, and `vcell` v0.1.x. If the `--nightly` flag is provided to
113+
//! `svd2rust`, then `msp430-atomic` v0.1.2 is also needed. Furthermore the "device" feature of
114+
//! `msp430-rt` must be enabled when the "rt" feature is enabled. The `Cargo.toml` of the device
115+
//! crate will look like this:
115116
//!
116117
//! ``` toml
117118
//! [dependencies]
118119
//! msp430 = "0.2.0"
119120
//! vcell = "0.1.0"
121+
//! msp430-atomic = "0.1.2" # Only when using the --nightly flag
120122
//!
121123
//! [dependencies.msp430-rt]
122124
//! optional = true
123125
//! version = "0.2.0"
124126
//!
125127
//! [features]
126128
//! rt = ["msp430-rt/device"]
129+
//! unstable = ["msp430-atomic"]
127130
//! ```
128131
//!
129132
//! ## Other targets
@@ -477,7 +480,23 @@
477480
//! ## the `--nightly` flag
478481
//!
479482
//! The `--nightly` flag can be passed to `svd2rust` to enable features in the generated api that are only available to a nightly
480-
//! compiler. Currently there are no nightly features the flag is only kept for compatibility with prior versions.
483+
//! compiler. The following features are gated by the `--nightly` flag:
484+
//!
485+
//! ### MSP430
486+
//!
487+
//! Extends the register API with operations to atomically set, clear, and toggle specific bits.
488+
//! The atomic operations allow limited modification of register bits without read-modify-write
489+
//! sequences. As such, they can be concurrently called on different bits in the same register
490+
//! without data races.
491+
//!
492+
//! Usage examples:
493+
//!
494+
//! ```ignore
495+
//! // These can be called from different contexts even though they are modifying the same register
496+
//! P1.p1out.set_bits(|w| unsafe { w.bits(1 << 1) });
497+
//! P1.p1out.clear(|w| unsafe { w.bits(!(1 << 2)) });
498+
//! P1.p1out.toggle(|w| unsafe { w.bits(1 << 4) });
499+
//! ```
481500
#![recursion_limit = "128"]
482501

483502
use quote::quote;

0 commit comments

Comments
 (0)