Skip to content

Proposal: User supplied scripts to add abstractions missing-from/impossible-in the input SVD. #186

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

Open
dunmatt opened this issue Mar 4, 2018 · 2 comments

Comments

@dunmatt
Copy link

dunmatt commented Mar 4, 2018

Problem:

Types generated by svd2rust are too specific to write reasonable HAL implementations.

Causal Factors:

SVD files are often garbage, and garbage in garbage out. Moreover, some reasonable types of abstraction can't be expressed within the SVD schema.

Motivating Example:

STM32F439x.svd has two peripherals within the <groupName> CAN; CAN1 and CAN2. As a consequence of this, the generated RegisterBlock for CAN2 is of type can1::RegisterBlock... which is wrong, because on this chip the two CAN peripherals have different sets of registers (see page 1120 of the reference manual ).

As if that's not bad enough, each CAN peripheral has 28 filter banks, each of which composed of two registers, each of which is rendered to its own type. So to implement a function add_filter that populates the next unused filterbank you have to hardcode the checking and manipulation of 56 registers (not counting the metadata registers that track things like whether a filter is in use)... and it'd be double that if the SVD wasn't incorrectly causing the two CAN peripherals to share a RegisterBlock.

What I would expect from a reasonable API, in this case, is a type hierarchy, a trait can::RegisterBlock, as well as the structs can1::RegisterBlock (which adds registers unique to can1) and can2::RegisterBlock (which adds nothing, only on account of it being a subset of can1). Within can::RegisterBlock I would expect an ordered collection of can::RegisterBlock::FilterBanks (which are themselves composed of the two registers).

So the question is, how can we get there from here?

Naive Proposal 1

Fix the SVD. SVD supports register cluster arrays, use them to group the 28 filterbanks. Sure, you'd still need a HAL implementation for each CAN Peripheral, but that's what macros are for!

There are a lot of problems with this approach:

  • Rewriting large portions of the SVD is a shit load of work, and it has to be repeated for every version of every SVD.
  • It can't express "the intersection of the specified perpherals" that could generate a trait. Macros can mitigate much of this problem, but at the cost of going from one code generator (svd2rust) to many (svd2rust plus the hand written macros for each generated crate).
  • It tends to burn people out. Talking to people on # rust-embedded who have gone down this road, they seem to prefer manually adding layers over the generated crate over fixing the input xml.

My (Naive?) Proposal

  1. Split svd2rust's compilation process into two phases; the first phase populates a map of SVD elements to their respective Tokens, and the second phase is to traverse the map, sending Tokens to the output. After this step there should be no change in svd2rust's behavior.
  2. Create a query engine for parsed svd (ie the results of the svd_parser crate) that resembles jQuery in function and form.
  3. Add a parameter to svd2rust that takes the name of a script, and run each query in the script against the map before it is serialized to the various output vectors.
  4. Use this to generate more flexible MCU crates.
@ryankurte
Copy link

I definitely agree with the problems, and some kind of scripted / mapping could be really useful.
Not sure that I like the macros for multiple HAL implementations concept so much.

You might be interested in #96 which is around automating common feature extraction etc. from svd files to solve both the duplicated peripherals per device and duplicated peripherals within device family problems.

I think the latest suggestion is a pipeline to pre-process batches of SVDs into more useful form (ie. with clusters and derives), then svd2rust into sensible packages.
Some kind of scripted approach like you propose would be really interesting in the pre-processing stage.

@robomancer-or
Copy link

That sounds remarkably similar to what I was proposing above, just with more modularity. It also looks like there hasn't been much activity in 6 months. Is there a way I can help? Perhaps defining a format to serve as your "more useful form"?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants