Skip to content

Commit e564d2d

Browse files
committed
always raw access
1 parent af7ba70 commit e564d2d

File tree

9 files changed

+526
-72
lines changed

9 files changed

+526
-72
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
3535

3636
## [v0.34.0] - 2024-11-05
3737

38+
- Add `raw-access` options
39+
3840
- Revert #711
3941
- Add `defmt` impls for `TryFromInterruptError`, riscv interrupt enums
4042
- Fix calculating `modifiedWriteValues` bitmasks with field arrays

src/config.rs

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ pub struct Config {
4040
pub ident_formats_theme: Option<IdentFormatsTheme>,
4141
pub field_names_for_enums: bool,
4242
pub base_address_shift: u64,
43+
pub raw_access: bool,
4344
/// Path to YAML file with chip-specific settings
4445
pub settings_file: Option<PathBuf>,
4546
/// Chip-specific settings

src/generate/device.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,11 @@ pub fn render(d: &Device, config: &Config, device_x: &mut String) -> Result<Toke
137137
}
138138

139139
let generic_file = include_str!("generic.rs");
140-
let generic_reg_file = include_str!("generic_reg_vcell.rs");
140+
let generic_reg_file = if config.raw_access {
141+
include_str!("generic_reg_raw.rs")
142+
} else {
143+
include_str!("generic_reg_vcell.rs")
144+
};
141145
let generic_atomic_file = include_str!("generic_atomic.rs");
142146
if config.generic_mod {
143147
let mut file = File::create(

src/generate/generic.rs

-46
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,5 @@
11
use core::marker;
22

3-
/// Generic peripheral accessor
4-
pub struct Periph<RB, const A: usize> {
5-
_marker: marker::PhantomData<RB>,
6-
}
7-
8-
unsafe impl<RB, const A: usize> Send for Periph<RB, A> {}
9-
10-
impl<RB, const A: usize> Periph<RB, A> {
11-
///Pointer to the register block
12-
pub const PTR: *const RB = A as *const _;
13-
14-
///Return the pointer to the register block
15-
#[inline(always)]
16-
pub const fn ptr() -> *const RB {
17-
Self::PTR
18-
}
19-
20-
/// Steal an instance of this peripheral
21-
///
22-
/// # Safety
23-
///
24-
/// Ensure that the new instance of the peripheral cannot be used in a way
25-
/// that may race with any existing instances, for example by only
26-
/// accessing read-only or write-only registers, or by consuming the
27-
/// original peripheral and using critical sections to coordinate
28-
/// access between multiple new instances.
29-
///
30-
/// Additionally, other software such as HALs may rely on only one
31-
/// peripheral instance existing to ensure memory safety; ensure
32-
/// no stolen instances are passed to such software.
33-
pub unsafe fn steal() -> Self {
34-
Self {
35-
_marker: marker::PhantomData,
36-
}
37-
}
38-
}
39-
40-
impl<RB, const A: usize> core::ops::Deref for Periph<RB, A> {
41-
type Target = RB;
42-
43-
#[inline(always)]
44-
fn deref(&self) -> &Self::Target {
45-
unsafe { &*Self::PTR }
46-
}
47-
}
48-
493
/// Raw register type (`u8`, `u16`, `u32`, ...)
504
pub trait RawReg:
515
Copy

src/generate/generic_reg_raw.rs

+301
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,301 @@
1+
/// This structure provides unsafe volatile access to registers.
2+
pub struct Reg<REG: RegisterSpec> {
3+
ptr: *mut u8,
4+
_marker: marker::PhantomData<REG>,
5+
}
6+
7+
unsafe impl<REG: RegisterSpec> Send for Reg<REG> where REG::Ux: Send {}
8+
9+
impl<REG: RegisterSpec> Reg<REG> {
10+
#[inline(always)]
11+
pub const fn new(ptr: *mut u8) -> Self {
12+
Self {
13+
ptr,
14+
_marker: marker::PhantomData,
15+
}
16+
}
17+
/// Returns the underlying memory address of register.
18+
///
19+
/// ```ignore
20+
/// let reg_ptr = periph.reg.as_ptr();
21+
/// ```
22+
#[inline(always)]
23+
pub const fn as_ptr(&self) -> *mut REG::Ux {
24+
self.ptr.cast()
25+
}
26+
}
27+
28+
impl<REG: Readable> Reg<REG> {
29+
/// Reads the contents of a `Readable` register.
30+
///
31+
/// You can read the raw contents of a register by using `bits`:
32+
/// ```ignore
33+
/// let bits = periph.reg.read().bits();
34+
/// ```
35+
/// or get the content of a particular field of a register:
36+
/// ```ignore
37+
/// let reader = periph.reg.read();
38+
/// let bits = reader.field1().bits();
39+
/// let flag = reader.field2().bit_is_set();
40+
/// ```
41+
#[inline(always)]
42+
pub unsafe fn read(&self) -> R<REG> {
43+
R {
44+
bits: self.as_ptr().read_volatile(),
45+
_reg: marker::PhantomData,
46+
}
47+
}
48+
}
49+
50+
impl<REG: Resettable + Writable> Reg<REG> {
51+
/// Writes the reset value to `Writable` register.
52+
///
53+
/// Resets the register to its initial state.
54+
#[inline(always)]
55+
pub unsafe fn reset(&self) {
56+
self.as_ptr().write_volatile(REG::RESET_VALUE)
57+
}
58+
59+
/// Writes bits to a `Writable` register.
60+
///
61+
/// You can write raw bits into a register:
62+
/// ```ignore
63+
/// periph.reg.write(|w| unsafe { w.bits(rawbits) });
64+
/// ```
65+
/// or write only the fields you need:
66+
/// ```ignore
67+
/// periph.reg.write(|w| w
68+
/// .field1().bits(newfield1bits)
69+
/// .field2().set_bit()
70+
/// .field3().variant(VARIANT)
71+
/// );
72+
/// ```
73+
/// or an alternative way of saying the same:
74+
/// ```ignore
75+
/// periph.reg.write(|w| {
76+
/// w.field1().bits(newfield1bits);
77+
/// w.field2().set_bit();
78+
/// w.field3().variant(VARIANT)
79+
/// });
80+
/// ```
81+
/// In the latter case, other fields will be set to their reset value.
82+
#[inline(always)]
83+
pub unsafe fn write<F>(&self, f: F) -> REG::Ux
84+
where
85+
F: FnOnce(&mut W<REG>) -> &mut W<REG>,
86+
{
87+
let value = f(&mut W {
88+
bits: REG::RESET_VALUE & !REG::ONE_TO_MODIFY_FIELDS_BITMAP
89+
| REG::ZERO_TO_MODIFY_FIELDS_BITMAP,
90+
_reg: marker::PhantomData,
91+
})
92+
.bits;
93+
self.as_ptr().write_volatile(value);
94+
value
95+
}
96+
97+
/// Writes bits to a `Writable` register and produce a value.
98+
///
99+
/// You can write raw bits into a register:
100+
/// ```ignore
101+
/// periph.reg.write_and(|w| unsafe { w.bits(rawbits); });
102+
/// ```
103+
/// or write only the fields you need:
104+
/// ```ignore
105+
/// periph.reg.write_and(|w| {
106+
/// w.field1().bits(newfield1bits)
107+
/// .field2().set_bit()
108+
/// .field3().variant(VARIANT);
109+
/// });
110+
/// ```
111+
/// or an alternative way of saying the same:
112+
/// ```ignore
113+
/// periph.reg.write_and(|w| {
114+
/// w.field1().bits(newfield1bits);
115+
/// w.field2().set_bit();
116+
/// w.field3().variant(VARIANT);
117+
/// });
118+
/// ```
119+
/// In the latter case, other fields will be set to their reset value.
120+
///
121+
/// Values can be returned from the closure:
122+
/// ```ignore
123+
/// let state = periph.reg.write_and(|w| State::set(w.field1()));
124+
/// ```
125+
#[inline(always)]
126+
pub fn from_write<F, T>(&self, f: F) -> T
127+
where
128+
F: FnOnce(&mut W<REG>) -> T,
129+
{
130+
let mut writer = W {
131+
bits: REG::RESET_VALUE & !REG::ONE_TO_MODIFY_FIELDS_BITMAP
132+
| REG::ZERO_TO_MODIFY_FIELDS_BITMAP,
133+
_reg: marker::PhantomData,
134+
};
135+
let result = f(&mut writer);
136+
137+
self.as_ptr().write_volatile(writer.bits);
138+
139+
result
140+
}
141+
}
142+
143+
impl<REG: Writable> Reg<REG> {
144+
/// Writes 0 to a `Writable` register.
145+
///
146+
/// Similar to `write`, but unused bits will contain 0.
147+
///
148+
/// # Safety
149+
///
150+
/// Unsafe to use with registers which don't allow to write 0.
151+
#[inline(always)]
152+
pub unsafe fn write_with_zero<F>(&self, f: F)
153+
where
154+
F: FnOnce(&mut W<REG>) -> &mut W<REG>,
155+
{
156+
let value = f(&mut W {
157+
bits: REG::Ux::default(),
158+
_reg: marker::PhantomData,
159+
})
160+
.bits;
161+
self.as_ptr().write_volatile(value);
162+
value
163+
}
164+
165+
/// Writes 0 to a `Writable` register and produces a value.
166+
///
167+
/// Similar to `write`, but unused bits will contain 0.
168+
///
169+
/// # Safety
170+
///
171+
/// Unsafe to use with registers which don't allow to write 0.
172+
#[inline(always)]
173+
pub unsafe fn from_write_with_zero<F, T>(&self, f: F) -> T
174+
where
175+
F: FnOnce(&mut W<REG>) -> T,
176+
{
177+
let mut writer = W {
178+
bits: REG::Ux::default(),
179+
_reg: marker::PhantomData,
180+
};
181+
182+
let result = f(&mut writer);
183+
184+
self.as_ptr().write_volatile(writer.bits);
185+
186+
result
187+
}
188+
}
189+
190+
impl<REG: Readable + Writable> Reg<REG> {
191+
/// Modifies the contents of the register by reading and then writing it.
192+
///
193+
/// E.g. to do a read-modify-write sequence to change parts of a register:
194+
/// ```ignore
195+
/// periph.reg.modify(|r, w| unsafe { w.bits(
196+
/// r.bits() | 3
197+
/// ) });
198+
/// ```
199+
/// or
200+
/// ```ignore
201+
/// periph.reg.modify(|_, w| w
202+
/// .field1().bits(newfield1bits)
203+
/// .field2().set_bit()
204+
/// .field3().variant(VARIANT)
205+
/// );
206+
/// ```
207+
/// or an alternative way of saying the same:
208+
/// ```ignore
209+
/// periph.reg.modify(|_, w| {
210+
/// w.field1().bits(newfield1bits);
211+
/// w.field2().set_bit();
212+
/// w.field3().variant(VARIANT)
213+
/// });
214+
/// ```
215+
/// Other fields will have the value they had before the call to `modify`.
216+
#[inline(always)]
217+
pub unsafe fn modify<F>(&self, f: F)
218+
where
219+
for<'w> F: FnOnce(&R<REG>, &'w mut W<REG>) -> &'w mut W<REG>,
220+
{
221+
let bits = self.as_ptr().read_volatile();
222+
let value = f(
223+
&R {
224+
bits,
225+
_reg: marker::PhantomData,
226+
},
227+
&mut W {
228+
bits: bits & !REG::ONE_TO_MODIFY_FIELDS_BITMAP | REG::ZERO_TO_MODIFY_FIELDS_BITMAP,
229+
_reg: marker::PhantomData,
230+
},
231+
)
232+
.bits;
233+
self.as_ptr().write_volatile(value);
234+
value
235+
}
236+
237+
/// Modifies the contents of the register by reading and then writing it
238+
/// and produces a value.
239+
///
240+
/// E.g. to do a read-modify-write sequence to change parts of a register:
241+
/// ```ignore
242+
/// let bits = periph.reg.modify(|r, w| {
243+
/// let new_bits = r.bits() | 3;
244+
/// unsafe {
245+
/// w.bits(new_bits);
246+
/// }
247+
///
248+
/// new_bits
249+
/// });
250+
/// ```
251+
/// or
252+
/// ```ignore
253+
/// periph.reg.modify(|_, w| {
254+
/// w.field1().bits(newfield1bits)
255+
/// .field2().set_bit()
256+
/// .field3().variant(VARIANT);
257+
/// });
258+
/// ```
259+
/// or an alternative way of saying the same:
260+
/// ```ignore
261+
/// periph.reg.modify(|_, w| {
262+
/// w.field1().bits(newfield1bits);
263+
/// w.field2().set_bit();
264+
/// w.field3().variant(VARIANT);
265+
/// });
266+
/// ```
267+
/// Other fields will have the value they had before the call to `modify`.
268+
#[inline(always)]
269+
pub fn from_modify<F, T>(&self, f: F) -> T
270+
where
271+
for<'w> F: FnOnce(&R<REG>, &'w mut W<REG>) -> T,
272+
{
273+
let bits = self.as_ptr().read_volatile();
274+
275+
let mut writer = W {
276+
bits: bits & !REG::ONE_TO_MODIFY_FIELDS_BITMAP | REG::ZERO_TO_MODIFY_FIELDS_BITMAP,
277+
_reg: marker::PhantomData,
278+
};
279+
280+
let result = f(
281+
&R {
282+
bits,
283+
_reg: marker::PhantomData,
284+
},
285+
&mut writer,
286+
);
287+
288+
self.as_ptr().write_volatile(writer.bits);
289+
290+
result
291+
}
292+
}
293+
294+
impl<REG: Readable> core::fmt::Debug for crate::generic::Reg<REG>
295+
where
296+
R<REG>: core::fmt::Debug,
297+
{
298+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
299+
unsafe { core::fmt::Debug::fmt(&self.read(), f) }
300+
}
301+
}

0 commit comments

Comments
 (0)