Skip to content

Commit 60aa7be

Browse files
committed
Emit more Cluster arrays as arrays instead of lists of elements.
Add ArrayProxy for handling Cluster arrays that would be emitted as a rust array except for the need for padding between elements.
1 parent e0860b7 commit 60aa7be

File tree

3 files changed

+80
-1
lines changed

3 files changed

+80
-1
lines changed

CHANGELOG.md

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

1010
- Support for device.x generation for riscv targets and `__EXTERNAL_INTERRUPTS` vector table
1111
- Re-export base's module for derived peripherals
12+
- More Cluster arrays are now emitted as an array rather than a list of
13+
elements. An `ArrayProxy` wrapper is used when a Rust built-in array does not
14+
match the cluster layout.
1215

1316
## [v0.19.0] - 2021-05-26
1417

src/generate/generic.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,3 +280,49 @@ impl<FI> FieldReader<bool, FI> {
280280
self.bit()
281281
}
282282
}
283+
284+
/// Access an array of `COUNT` items of type `T` with the items `STRIDE` bytes
285+
/// apart. This is a zero-sized-type. No objects of this type are ever
286+
/// actually created, it is only a convenience for wrapping pointer arithmetic.
287+
///
288+
/// There is no safe way to produce items of this type. Unsafe code can produce
289+
/// references by pointer casting. It is up to the unsafe code doing that, to
290+
/// ensure that the memory really is backed by appropriate content.
291+
///
292+
/// Typically, this is used for accessing hardware registers.
293+
pub struct ArrayProxy<T, const COUNT: usize, const STRIDE: usize> {
294+
/// As well as providing a PhantomData, this field is non-public, and
295+
/// therefore ensures that code outside of this module can never create
296+
/// an ArrayProxy.
297+
_array: marker::PhantomData<T>
298+
}
299+
300+
impl<T, const C: usize, const S: usize> ArrayProxy<T, C, S> {
301+
/// Get a reference from an [ArrayProxy] with no bounds checking.
302+
pub unsafe fn get_ref(&self, index: usize) -> &T {
303+
let base = self as *const Self as usize;
304+
let address = base + S * index;
305+
&*(address as *const T)
306+
}
307+
/// Get a reference from an [ArrayProxy], or return `None` if the index
308+
/// is out of bounds.
309+
pub fn get(&self, index: usize) -> Option<&T> {
310+
if index < C {
311+
Some(unsafe { self.get_ref(index) })
312+
}
313+
else {
314+
None
315+
}
316+
}
317+
/// Return the number of items.
318+
pub fn len(&self) -> usize { C }
319+
}
320+
321+
impl<T, const C: usize, const S: usize> core::ops::Index<usize> for ArrayProxy<T, C, S> {
322+
type Output = T;
323+
fn index(&self, index: usize) -> &T {
324+
// Do a real array dereference for the bounds check.
325+
[(); C][index];
326+
unsafe { self.get_ref(index) }
327+
}
328+
}

src/generate/peripheral.rs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ use std::borrow::Cow;
22
use std::cmp::Ordering;
33
use std::collections::HashMap;
44

5-
use crate::svd::{Cluster, ClusterInfo, Peripheral, Register, RegisterCluster, RegisterProperties};
5+
use crate::svd::{
6+
Cluster, ClusterInfo, DimElement, Peripheral, Register, RegisterCluster, RegisterProperties,
7+
};
68
use log::warn;
79
use proc_macro2::TokenStream;
810
use proc_macro2::{Ident, Punct, Spacing, Span};
@@ -701,6 +703,10 @@ fn expand_cluster(
701703
offset: info.address_offset,
702704
size: cluster_size * array_info.dim,
703705
});
706+
} else if sequential_indexes {
707+
// Include a ZST ArrayProxy giving indexed access to the
708+
// elements.
709+
cluster_expanded.push(array_proxy(info, array_info, name)?);
704710
} else {
705711
for (field_num, field) in expand_svd_cluster(cluster, name)?.iter().enumerate() {
706712
cluster_expanded.push(RegisterBlockField {
@@ -901,6 +907,30 @@ fn convert_svd_register(
901907
})
902908
}
903909

910+
/// Return an syn::Type for an ArrayProxy.
911+
fn array_proxy(
912+
info: &ClusterInfo,
913+
array_info: &DimElement,
914+
name: Option<&str>,
915+
) -> Result<RegisterBlockField, syn::Error> {
916+
let ty_name = util::replace_suffix(&info.name, "");
917+
let tys = name_to_ty_str(&ty_name, name);
918+
919+
let ap_path = parse_str::<syn::TypePath>(&format!(
920+
"crate::ArrayProxy<{}, {}, {}>",
921+
tys,
922+
array_info.dim,
923+
util::hex(array_info.dim_increment as u64)
924+
))?;
925+
926+
Ok(RegisterBlockField {
927+
field: new_syn_field(&ty_name.to_sanitized_snake_case(), ap_path.into()),
928+
description: info.description.as_ref().unwrap_or(&info.name).into(),
929+
offset: info.address_offset,
930+
size: 0,
931+
})
932+
}
933+
904934
/// Takes a svd::Cluster which may contain a register array, and turn in into
905935
/// a list of syn::Field where the register arrays have been expanded.
906936
fn expand_svd_cluster(

0 commit comments

Comments
 (0)