Skip to content

add code generation support of peripheral arrays #592

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Apr 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased]

- Optional PascalCase for Enum values instead of UPPER_CASE
- Add code generation support of peripheral arrays.

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

Expand Down
10 changes: 5 additions & 5 deletions src/generate/array_proxy.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

/// Access an array of `COUNT` items of type `T` with the items `STRIDE` bytes
/// apart. This is a zero-sized-type. No objects of this type are ever
/// actually created, it is only a convenience for wrapping pointer arithmetic.
Expand All @@ -12,7 +11,7 @@ pub struct ArrayProxy<T, const COUNT: usize, const STRIDE: usize> {
/// As well as providing a PhantomData, this field is non-public, and
/// therefore ensures that code outside of this module can never create
/// an ArrayProxy.
_array: marker::PhantomData<T>
_array: marker::PhantomData<T>,
}

impl<T, const C: usize, const S: usize> ArrayProxy<T, C, S> {
Expand All @@ -27,13 +26,14 @@ impl<T, const C: usize, const S: usize> ArrayProxy<T, C, S> {
pub fn get(&self, index: usize) -> Option<&T> {
if index < C {
Some(unsafe { self.get_ref(index) })
}
else {
} else {
None
}
}
/// Return the number of items.
pub fn len(&self) -> usize { C }
pub fn len(&self) -> usize {
C
}
}

impl<T, const C: usize, const S: usize> core::ops::Index<usize> for ArrayProxy<T, C, S> {
Expand Down
35 changes: 27 additions & 8 deletions src/generate/device.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use crate::svd::Device;
use crate::svd::{array::names, Device, Peripheral};
use proc_macro2::{Ident, Span, TokenStream};
use quote::{quote, ToTokens};

use log::debug;
use std::borrow::Cow;
use std::fs::File;
use std::io::Write;

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

let p = p.name.to_sanitized_upper_case();
let id = Ident::new(&p, Span::call_site());
fields.extend(quote! {
#[doc = #p]
pub #id: #id,
});
exprs.extend(quote!(#id: #id { _marker: PhantomData },));
match p {
Peripheral::Single(_p) => {
let p_name = util::name_of(p, config.ignore_groups);
let p = p_name.to_sanitized_upper_case();
let id = Ident::new(&p, Span::call_site());
fields.extend(quote! {
#[doc = #p]
pub #id: #id,
});
exprs.extend(quote!(#id: #id { _marker: PhantomData },));
}
Peripheral::Array(_p, dim_element) => {
let p_names: Vec<Cow<str>> = names(p, dim_element).map(|n| n.into()).collect();
let p = p_names.iter().map(|p| p.to_sanitized_upper_case());
let ids_f = p.clone().map(|p| Ident::new(&p, Span::call_site()));
let ids_e = ids_f.clone();
fields.extend(quote! {
#(
#[doc = #p]
pub #ids_f: #ids_f,
)*
});
exprs.extend(quote!(#(#ids_e: #ids_e { _marker: PhantomData },)*));
}
}
}

let span = Span::call_site();
Expand Down
111 changes: 80 additions & 31 deletions src/generate/peripheral.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use std::cmp::Ordering;
use std::collections::HashMap;

use crate::svd::{
Cluster, ClusterInfo, DeriveFrom, DimElement, Peripheral, Register, RegisterCluster,
RegisterProperties,
array::names, Cluster, ClusterInfo, DeriveFrom, DimElement, Peripheral, Register,
RegisterCluster, RegisterProperties,
};
use log::{debug, trace, warn};
use proc_macro2::{Ident, Punct, Spacing, Span, TokenStream};
Expand Down Expand Up @@ -43,52 +43,100 @@ pub fn render(
return Ok(out);
}

let name = util::name_of(p, config.ignore_groups);
let span = Span::call_site();
let name_str = p.name.to_sanitized_upper_case();
let name_str = name.to_sanitized_upper_case();
let name_pc = Ident::new(&name_str, span);
let address = util::hex(p.base_address as u64);
let description = util::respace(p.description.as_ref().unwrap_or(&p.name));

let name_sc = Ident::new(&p.name.to_sanitized_snake_case(), span);
let name_sc = Ident::new(&name.to_sanitized_snake_case(), span);
let (derive_regs, base) = if let (Some(df), None) = (p_derivedfrom, &p_original.registers) {
(true, Ident::new(&df.name.to_sanitized_snake_case(), span))
} else {
(false, name_sc.clone())
};

// Insert the peripheral structure
out.extend(quote! {
#[doc = #description]
pub struct #name_pc { _marker: PhantomData<*const ()> }
match p_original {
Peripheral::Array(p, dim) => {
let names: Vec<Cow<str>> = names(p, dim).map(|n| n.into()).collect();
let names_str = names.iter().map(|n| n.to_sanitized_upper_case());
let names_pc = names_str.clone().map(|n| Ident::new(&n, span));
let addresses =
(0..=dim.dim).map(|i| util::hex(p.base_address + (i * dim.dim_increment) as u64));

// Insert the peripherals structure
out.extend(quote! {
#(
#[doc = #description]
pub struct #names_pc { _marker: PhantomData<*const ()> }

unsafe impl Send for #names_pc {}

impl #names_pc {
///Pointer to the register block
pub const PTR: *const #base::RegisterBlock = #addresses as *const _;

///Return the pointer to the register block
#[inline(always)]
pub const fn ptr() -> *const #base::RegisterBlock {
Self::PTR
}
}

unsafe impl Send for #name_pc {}
impl Deref for #names_pc {
type Target = #base::RegisterBlock;

impl #name_pc {
///Pointer to the register block
pub const PTR: *const #base::RegisterBlock = #address as *const _;
#[inline(always)]
fn deref(&self) -> &Self::Target {
unsafe { &*Self::PTR }
}
}

///Return the pointer to the register block
#[inline(always)]
pub const fn ptr() -> *const #base::RegisterBlock {
Self::PTR
}
impl core::fmt::Debug for #names_pc {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
f.debug_struct(#names_str).finish()
}
}
)*
});
}
_ => {
// Insert the peripheral structure
out.extend(quote! {
#[doc = #description]
pub struct #name_pc { _marker: PhantomData<*const ()> }

impl Deref for #name_pc {
type Target = #base::RegisterBlock;
unsafe impl Send for #name_pc {}

#[inline(always)]
fn deref(&self) -> &Self::Target {
unsafe { &*Self::PTR }
}
}
impl #name_pc {
///Pointer to the register block
pub const PTR: *const #base::RegisterBlock = #address as *const _;

impl core::fmt::Debug for #name_pc {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
f.debug_struct(#name_str).finish()
}
///Return the pointer to the register block
#[inline(always)]
pub const fn ptr() -> *const #base::RegisterBlock {
Self::PTR
}
}

impl Deref for #name_pc {
type Target = #base::RegisterBlock;

#[inline(always)]
fn deref(&self) -> &Self::Target {
unsafe { &*Self::PTR }
}
}

impl core::fmt::Debug for #name_pc {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
f.debug_struct(#name_str).finish()
}
}
});
}
});
}

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

let description =
util::escape_brackets(util::respace(p.description.as_ref().unwrap_or(&p.name)).as_ref());
let description = util::escape_brackets(
util::respace(p.description.as_ref().unwrap_or(&name.as_ref().to_owned())).as_ref(),
);

let open = Punct::new('{', Spacing::Alone);
let close = Punct::new('}', Spacing::Alone);
Expand Down
15 changes: 11 additions & 4 deletions src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use inflections::Inflect;
use proc_macro2::{Ident, Literal, Span, TokenStream};
use quote::{quote, ToTokens};
use std::path::{Path, PathBuf};
use svd_rs::{MaybeArray, PeripheralInfo};

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

Expand Down Expand Up @@ -221,10 +222,10 @@ pub fn escape_brackets(s: &str) -> String {
})
}

pub fn name_of(register: &Register, ignore_group: bool) -> Cow<str> {
match register {
Register::Single(info) => info.fullname(ignore_group),
Register::Array(info, _) => replace_suffix(&info.fullname(ignore_group), "").into(),
pub fn name_of<T: FullName>(maybe_array: &MaybeArray<T>, ignore_group: bool) -> Cow<str> {
match maybe_array {
MaybeArray::Single(info) => info.fullname(ignore_group),
MaybeArray::Array(info, _) => replace_suffix(&info.fullname(ignore_group), "").into(),
}
}

Expand Down Expand Up @@ -445,3 +446,9 @@ impl FullName for RegisterInfo {
}
}
}

impl FullName for PeripheralInfo {
fn fullname(&self, _ignore_group: bool) -> Cow<str> {
self.name.as_str().into()
}
}