svd2rust icon indicating copy to clipboard operation
svd2rust copied to clipboard

Multiple MCU models in a single crate using cfg features

Open maximeborges opened this issue 5 years ago • 6 comments

I was wondering if it was possible to make a single crate from multiple SVDs. Basically, merging all the common registers and peripherals, and compiling only what is needed.

After playing a bit with the code and SVDs from Silabs (EFM32), I think it would be quite easy to build a single crate using conditional compilation using cfg features that compile only what is needed.

Since this goal seemed a bit easy, I was thinking why projects like https://github.com/stm32-rs/stm32-rs were making crates with a way more complicated structure (besides fixing errors from the manufacturer, which could also be merged in svd2rust IMO).

Is there any reasons why this wasn't done ? If it seems to be a good idea, I can try to implement that in the next few days.

maximeborges avatar Oct 28 '19 19:10 maximeborges

The only reason is nobody could do it properly.

burrbull avatar Oct 29 '19 05:10 burrbull

it's a neat idea! as @burrbull mentioned it is difficult, though the silicon labs ICs would be an excellent candidate for something like this as (at least within a generation) they are very similar internally.

you might be interested to look at: https://github.com/rust-embedded/svd2rust/issues/96 for related discussion (though i think we were proposing that per-device files re-export the right set of peripherals rather than using configuration variables as they can get gnarley)

ryankurte avatar Oct 29 '19 05:10 ryankurte

The stm32-rs crates have quite a simple structure I think: it's just one module per device, and each module is cfg-gated so when you build you only get your one device. Only what is needed is compiled. The structure means there's only one crate per family instead of having a hundred crates, and there's one per family instead of just one stm32 crate because of crate file size limits.

I think the only advantage of merging common peripherals and registers between multiple SVDs is reducing actual code size on disk, since you don't compile what you're not using anyway. That's exactly what I do in stm32ral which does a lot of work to extract identical registers and peripherals between members of each family (and at one point between families). It won't surprise anyone who's looked at the ST SVDs to hear that a million tiny differences ruin your day surprisingly quickly. For example, most parts have almost identical GPIOA compared to GPIOB and GPIOC, but often a different reset value on the default mode to have JTAG be the boot default. That alone is enough to stop them being merged together.

Overall I'd love to see svd2rust take a similar approach, where you feed it multiple SVDs and it produces a crate that has all the common registers factored out, but it's not trivial and often the SVD quality is what determines whether you'll succeed at all.

adamgreig avatar Oct 29 '19 12:10 adamgreig

often the SVD quality is what determines whether you'll succeed at all

Anyone actually tried to contact some manufacturers to ask them to fix the SVDs ? Making patches is not really the best thing to do IMO, and it would be much easier to have tools that don't need to monkey-patch manufacturer files.

For example, most parts have almost identical GPIOA compared to GPIOB and GPIOC, but often a different reset value on the default mode to have JTAG be the boot default. That alone is enough to stop them being merged together.

Since you can put cfg feature on basically anything according to my tests, is it really a problem ? I don't really have a lot of experience with Rust.

Also would it be cleaner to use a file structure similar to what stm32-rs is doing (familly->cfg'd modules->single MCU) or more something like a said (familly->cfg'ed registers/peripherals) ?

I could start working on it soon, so if anyone has any reasons to say one way is better than the other, express yourself (or if you come up with better ideas).

maximeborges avatar Oct 29 '19 20:10 maximeborges

@adamgreig

Overall I'd love to see svd2rust take a similar approach, where you feed it multiple SVDs and it produces a crate that has all the common registers factored out, but it's not trivial and often the SVD quality is what determines whether you'll succeed at all.

That would be very useful, even without common registers factored out. We've recently moved lpc8xx-hal from the nrf52-hal-style "one HAL crate per target" approach to the stm32-rs-style "one HAL crate for all targets" approach. As a result, we now have one runtime feature per target, as there's no way (to my knowledge) to enable the rt feature of just the PAC you want to depend on.

Being able to easily create stm32-rs-style PACs, with one module per target, would fix this situation for us.

@maximeborges

Anyone actually tried to contact some manufacturers to ask them to fix the SVDs ? Making patches is not really the best thing to do IMO, and it would be much easier to have tools that don't need to monkey-patch manufacturer files.

NXP has been very receptive to my bug reports. You have to know how to talk to them (filing a support request on their website is reliable; posting in their community forum is more hit-and-miss), but since I've figured that out, each report has resulted in an updated SVD file with their next SDK release.

hannobraun avatar Oct 30 '19 07:10 hannobraun

Is this model compatible with multiple different cores share common peripherals? For example NXP's RV32M1 consists of 4 different cores (2 different RISC-V, 2 different Cortex-M), but inside this chip all these cores share common peripheral; for each pir one RISC-V and one CM core share one group of peripheral. Rust developer may benefit from using cfg features for each core to decide which peripheral this core have access to.

luojia65 avatar Mar 02 '20 03:03 luojia65