Skip to content

Commit 040f9d4

Browse files
Merge #592
592: add code generation support of peripheral arrays r=burrbull a=duskmoon314 ## Brief Intro - generate ArrayProxy of peripherals when const_generic is true - generate separate struct of peripherals when const_generic is false close issue: #492 ## Design **Notice:** This is my first try of implement this feature. Please provide suggestions for this PR to better implement this feature. This PR aims to achieve what issue #492 is asking for. This PR implements a basic try of generating codes depending on the `const_generic` flag. Let's say we have an svd file with descriptions of peripherals like this: ```XML <peripheral> <dim>2</dim> <dimIncrement>0x100</dimIncrement> <name>PTEST[%s]</name> <groupName>PGroup</groupName> <baseAddress>0x20000000</baseAddress> <addressBlock> <offset>0</offset> <size>0x100</size> <usage>registers</usage> </addressBlock> <registers> ... </registers> </peripheral> ``` If the `const_generic` is `false`, there is no `ArrayProxy`. So I generate separate structs and only one mod: ```rust pub struct PTEST0 { _marker: PhantomData<*const ()>, } ... impl PTEST0 { #[doc = r"Pointer to the register block"] pub const PTR: *const ptest::RegisterBlock = 0x2000_0000 as *const _; ... } impl Deref for PTEST0 { type Target = ptest::RegisterBlock; #[inline(always)] fn deref(&self) -> &Self::Target { unsafe { &*Self::PTR } } } pub struct PTEST1 { _marker: PhantomData<*const ()>, } ... impl PTEST1 { #[doc = r"Pointer to the register block"] pub const PTR: *const ptest::RegisterBlock = 0x2000_0100 as *const _; ... } impl Deref for PTEST1 { type Target = ptest::RegisterBlock; #[inline(always)] fn deref(&self) -> &Self::Target { unsafe { &*Self::PTR } } } #[doc = "PTEST"] pub mod ptest; ``` **NOTICE:** The following design is actually incorrect and has been removed. See the following comment. <details> If the `const_generic` is `true`, we can use `ArrayProxy`. So I generate code like this: ```rust pub struct PTEST { _marker: PhantomData<*const ()>, } ... pub struct Peripherals { #[doc = "PTEST"] pub PTEST: crate::ArrayProxy<PTEST, 2usize, 0x0100>, ... impl Peripherals { ... pub unsafe fn steal() -> Self { DEVICE_PERIPHERALS = true; Peripherals { PTEST: crate::ArrayProxy::new(), ``` Since `_array` is a private field of `ArrayProxy`, I add a `new` method to implement the `steal` method of `Peripherals`. </details> I also add the support of using `name_of` on `MaybeArray<PeripheralInfo>` to achieve this implementation. Well, I haven't fully tested this implementation yet. So there may be problems that need to be solved. Co-authored-by: Campbell He <campbell.he@icloud.com> Co-authored-by: Campbell He <duskmoon314@users.noreply.github.com>
2 parents c1085b3 + aeda2a3 commit 040f9d4

File tree

5 files changed

+124
-48
lines changed

5 files changed

+124
-48
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1010
- Generate const generic version of field array only if `const_generic` enabled
1111
- Clean `FieldReader`
1212
- Optional PascalCase for Enum values instead of UPPER_CASE
13+
- Add code generation support of peripheral arrays.
1314

1415
## [v0.22.2] - 2022-04-13
1516

src/generate/array_proxy.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
/// Access an array of `COUNT` items of type `T` with the items `STRIDE` bytes
32
/// apart. This is a zero-sized-type. No objects of this type are ever
43
/// actually created, it is only a convenience for wrapping pointer arithmetic.
@@ -12,7 +11,7 @@ pub struct ArrayProxy<T, const COUNT: usize, const STRIDE: usize> {
1211
/// As well as providing a PhantomData, this field is non-public, and
1312
/// therefore ensures that code outside of this module can never create
1413
/// an ArrayProxy.
15-
_array: marker::PhantomData<T>
14+
_array: marker::PhantomData<T>,
1615
}
1716

1817
impl<T, const C: usize, const S: usize> ArrayProxy<T, C, S> {
@@ -27,13 +26,14 @@ impl<T, const C: usize, const S: usize> ArrayProxy<T, C, S> {
2726
pub fn get(&self, index: usize) -> Option<&T> {
2827
if index < C {
2928
Some(unsafe { self.get_ref(index) })
30-
}
31-
else {
29+
} else {
3230
None
3331
}
3432
}
3533
/// Return the number of items.
36-
pub fn len(&self) -> usize { C }
34+
pub fn len(&self) -> usize {
35+
C
36+
}
3737
}
3838

3939
impl<T, const C: usize, const S: usize> core::ops::Index<usize> for ArrayProxy<T, C, S> {

src/generate/device.rs

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
use crate::svd::Device;
1+
use crate::svd::{array::names, Device, Peripheral};
22
use proc_macro2::{Ident, Span, TokenStream};
33
use quote::{quote, ToTokens};
44

55
use log::debug;
6+
use std::borrow::Cow;
67
use std::fs::File;
78
use std::io::Write;
89

@@ -236,13 +237,31 @@ pub fn render(d: &Device, config: &Config, device_x: &mut String) -> Result<Toke
236237
continue;
237238
}
238239

239-
let p = p.name.to_sanitized_upper_case();
240-
let id = Ident::new(&p, Span::call_site());
241-
fields.extend(quote! {
242-
#[doc = #p]
243-
pub #id: #id,
244-
});
245-
exprs.extend(quote!(#id: #id { _marker: PhantomData },));
240+
match p {
241+
Peripheral::Single(_p) => {
242+
let p_name = util::name_of(p, config.ignore_groups);
243+
let p = p_name.to_sanitized_upper_case();
244+
let id = Ident::new(&p, Span::call_site());
245+
fields.extend(quote! {
246+
#[doc = #p]
247+
pub #id: #id,
248+
});
249+
exprs.extend(quote!(#id: #id { _marker: PhantomData },));
250+
}
251+
Peripheral::Array(_p, dim_element) => {
252+
let p_names: Vec<Cow<str>> = names(p, dim_element).map(|n| n.into()).collect();
253+
let p = p_names.iter().map(|p| p.to_sanitized_upper_case());
254+
let ids_f = p.clone().map(|p| Ident::new(&p, Span::call_site()));
255+
let ids_e = ids_f.clone();
256+
fields.extend(quote! {
257+
#(
258+
#[doc = #p]
259+
pub #ids_f: #ids_f,
260+
)*
261+
});
262+
exprs.extend(quote!(#(#ids_e: #ids_e { _marker: PhantomData },)*));
263+
}
264+
}
246265
}
247266

248267
let span = Span::call_site();

src/generate/peripheral.rs

Lines changed: 80 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ use std::cmp::Ordering;
33
use std::collections::HashMap;
44

55
use crate::svd::{
6-
Cluster, ClusterInfo, DeriveFrom, DimElement, Peripheral, Register, RegisterCluster,
7-
RegisterProperties,
6+
array::names, Cluster, ClusterInfo, DeriveFrom, DimElement, Peripheral, Register,
7+
RegisterCluster, RegisterProperties,
88
};
99
use log::{debug, trace, warn};
1010
use proc_macro2::{Ident, Punct, Spacing, Span, TokenStream};
@@ -43,52 +43,100 @@ pub fn render(
4343
return Ok(out);
4444
}
4545

46+
let name = util::name_of(p, config.ignore_groups);
4647
let span = Span::call_site();
47-
let name_str = p.name.to_sanitized_upper_case();
48+
let name_str = name.to_sanitized_upper_case();
4849
let name_pc = Ident::new(&name_str, span);
4950
let address = util::hex(p.base_address as u64);
5051
let description = util::respace(p.description.as_ref().unwrap_or(&p.name));
5152

52-
let name_sc = Ident::new(&p.name.to_sanitized_snake_case(), span);
53+
let name_sc = Ident::new(&name.to_sanitized_snake_case(), span);
5354
let (derive_regs, base) = if let (Some(df), None) = (p_derivedfrom, &p_original.registers) {
5455
(true, Ident::new(&df.name.to_sanitized_snake_case(), span))
5556
} else {
5657
(false, name_sc.clone())
5758
};
5859

59-
// Insert the peripheral structure
60-
out.extend(quote! {
61-
#[doc = #description]
62-
pub struct #name_pc { _marker: PhantomData<*const ()> }
60+
match p_original {
61+
Peripheral::Array(p, dim) => {
62+
let names: Vec<Cow<str>> = names(p, dim).map(|n| n.into()).collect();
63+
let names_str = names.iter().map(|n| n.to_sanitized_upper_case());
64+
let names_pc = names_str.clone().map(|n| Ident::new(&n, span));
65+
let addresses =
66+
(0..=dim.dim).map(|i| util::hex(p.base_address + (i * dim.dim_increment) as u64));
67+
68+
// Insert the peripherals structure
69+
out.extend(quote! {
70+
#(
71+
#[doc = #description]
72+
pub struct #names_pc { _marker: PhantomData<*const ()> }
73+
74+
unsafe impl Send for #names_pc {}
75+
76+
impl #names_pc {
77+
///Pointer to the register block
78+
pub const PTR: *const #base::RegisterBlock = #addresses as *const _;
79+
80+
///Return the pointer to the register block
81+
#[inline(always)]
82+
pub const fn ptr() -> *const #base::RegisterBlock {
83+
Self::PTR
84+
}
85+
}
6386

64-
unsafe impl Send for #name_pc {}
87+
impl Deref for #names_pc {
88+
type Target = #base::RegisterBlock;
6589

66-
impl #name_pc {
67-
///Pointer to the register block
68-
pub const PTR: *const #base::RegisterBlock = #address as *const _;
90+
#[inline(always)]
91+
fn deref(&self) -> &Self::Target {
92+
unsafe { &*Self::PTR }
93+
}
94+
}
6995

70-
///Return the pointer to the register block
71-
#[inline(always)]
72-
pub const fn ptr() -> *const #base::RegisterBlock {
73-
Self::PTR
74-
}
96+
impl core::fmt::Debug for #names_pc {
97+
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
98+
f.debug_struct(#names_str).finish()
99+
}
100+
}
101+
)*
102+
});
75103
}
104+
_ => {
105+
// Insert the peripheral structure
106+
out.extend(quote! {
107+
#[doc = #description]
108+
pub struct #name_pc { _marker: PhantomData<*const ()> }
76109

77-
impl Deref for #name_pc {
78-
type Target = #base::RegisterBlock;
110+
unsafe impl Send for #name_pc {}
79111

80-
#[inline(always)]
81-
fn deref(&self) -> &Self::Target {
82-
unsafe { &*Self::PTR }
83-
}
84-
}
112+
impl #name_pc {
113+
///Pointer to the register block
114+
pub const PTR: *const #base::RegisterBlock = #address as *const _;
85115

86-
impl core::fmt::Debug for #name_pc {
87-
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
88-
f.debug_struct(#name_str).finish()
89-
}
116+
///Return the pointer to the register block
117+
#[inline(always)]
118+
pub const fn ptr() -> *const #base::RegisterBlock {
119+
Self::PTR
120+
}
121+
}
122+
123+
impl Deref for #name_pc {
124+
type Target = #base::RegisterBlock;
125+
126+
#[inline(always)]
127+
fn deref(&self) -> &Self::Target {
128+
unsafe { &*Self::PTR }
129+
}
130+
}
131+
132+
impl core::fmt::Debug for #name_pc {
133+
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
134+
f.debug_struct(#name_str).finish()
135+
}
136+
}
137+
});
90138
}
91-
});
139+
}
92140

93141
// Derived peripherals may not require re-implementation, and will instead
94142
// use a single definition of the non-derived version.
@@ -195,8 +243,9 @@ pub fn render(
195243
};
196244
}
197245

198-
let description =
199-
util::escape_brackets(util::respace(p.description.as_ref().unwrap_or(&p.name)).as_ref());
246+
let description = util::escape_brackets(
247+
util::respace(p.description.as_ref().unwrap_or(&name.as_ref().to_owned())).as_ref(),
248+
);
200249

201250
let open = Punct::new('{', Spacing::Alone);
202251
let close = Punct::new('}', Spacing::Alone);

src/util.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use inflections::Inflect;
77
use proc_macro2::{Ident, Literal, Span, TokenStream};
88
use quote::{quote, ToTokens};
99
use std::path::{Path, PathBuf};
10+
use svd_rs::{MaybeArray, PeripheralInfo};
1011

1112
use anyhow::{anyhow, bail, Context, Result};
1213

@@ -221,10 +222,10 @@ pub fn escape_brackets(s: &str) -> String {
221222
})
222223
}
223224

224-
pub fn name_of(register: &Register, ignore_group: bool) -> Cow<str> {
225-
match register {
226-
Register::Single(info) => info.fullname(ignore_group),
227-
Register::Array(info, _) => replace_suffix(&info.fullname(ignore_group), "").into(),
225+
pub fn name_of<T: FullName>(maybe_array: &MaybeArray<T>, ignore_group: bool) -> Cow<str> {
226+
match maybe_array {
227+
MaybeArray::Single(info) => info.fullname(ignore_group),
228+
MaybeArray::Array(info, _) => replace_suffix(&info.fullname(ignore_group), "").into(),
228229
}
229230
}
230231

@@ -445,3 +446,9 @@ impl FullName for RegisterInfo {
445446
}
446447
}
447448
}
449+
450+
impl FullName for PeripheralInfo {
451+
fn fullname(&self, _ignore_group: bool) -> Cow<str> {
452+
self.name.as_str().into()
453+
}
454+
}

0 commit comments

Comments
 (0)