-
Notifications
You must be signed in to change notification settings - Fork 151
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
proposal: separate crates for peripherals #902
Comments
I like the idea. I think it is last chunk of the puzzle.
Other notes:
|
So I've tried to implement 1 step but understood that I don't know how to do this. There are 2 issues:
But without this change splitting on different crates makes much less sense as each one will have it's own copy of register access implementation. I still like the idea as it gives possibility to create and publish independent crates much easier so HALs can reuse them. Like https://github.com/stm32-rs/bxcan Now to performance issues. I'd want to see on SVDs you are using to generate rust. The best way to improve performance is to reduce of code. You can do it by using register arrays, clusters and by using |
Wow, that is definitely the opposite of the goal of this proposal. Thank you for doing the experiment.
I had a similar thought when you brought up the module hashing, like the peripheral crates could be reused by other PACs and HALs. That may also require parameterizing the base address in some way (either on a
This was also brought up in the meeting yesterday, and it certainly seems like one of the first, most straightforward steps to take in reducing compile times (especially when one has full control over the SVD). However, I'm already heavily utilizing as much code re-use as possible. There is maybe a bit more re-use I could gain with the SVD attribute for saying a non-contiguous peripheral is based on another definition. For example, there are peripherals that are based on the same IP, but are not in contiguous memory.
The main PAC that I maintain is jh71xx-pac, and I use svd-generator to generate the SVD (the latter is where I could probably make some additional optimizations for code re-use). Here is a link to the jh71xx-pac SVD |
Yes. This is the first you should fix. For example UART1 should looks like <peripheral derivedFrom="uart0">
<name>uart1</name>
<groupName>UART</groupName>
<description>Synopsys DesignWare APB UART: uart1</description>
<baseAddress>0x10010000</baseAddress>
<addressBlock>
<offset>0x0</offset>
<size>0x10000</size>
<usage>registers</usage>
</addressBlock>
<interrupt>
<name>UART1</name>
<value>33</value>
</interrupt>
</peripheral> No Besides code reduce this also gives you possibility to write generic (over peripheral) code in your HAL instead of macros. P.S. You could also try to use patched version of |
So, I followed your advice, and applied the It shaved off ~72k LoC, and ~17-20 seconds from CI compile time! Going to try it on a low-resource, multicore SBC now. This is encouraging. I think if we can further improve with parallelizing the PAC build as much as possible, it will greatly improve compile times. Locally, there is still a period where there seems to be a single core pinged with other idle cores. Edit: attempted the build with reduced code on the low-resource SBC. There was a small time-savings, but the debug build still takes ~3min with the majority spent in the final stage compiling Going to try splitting the crate manually to see how much time saving there is. |
Reposting a comment I left in the So, I tried a bit of an experiment manually splitting out the peripheral modules into crates. From the bit of work done, it requires splitting out the The Instead, the aliases turn into wrapper types: pub struct R(generic::R);
pub struct W(generic::W);
impl R {
pub const fn field(&self) -> FieldR {
FieldR::new(self.0.bits() & field_mask)
}
}
impl W {
pub fn field(&mut self) -> FieldW<FieldSpec> {
FieldW::new(self, 0)
}
} Going to take a bit to do that programmatically in
It's not clear at the moment, but one potential option would be to define the peripherals with the following pseudo-Rust: pub extern crate some_peripheral {
// alll the peripheral code that would normally go in the module
} Then, after the pub extern crate some_peripheral; |
Have you tried to implement it? That is the question. How do you suggest to avoid code duplication? Of each |
Yes, but only had success with a manual implementation of a single small peripheral ( I tried some additional experiments with programmatic implementation in
That is definitely an issue. It may require a complete restructuring of the Through these experiments, I keep wondering about defining PACs per-peripheral instead of at the SoC level. I know this was not the original intention of SVD, but peripherals are shared across a number of different SoCs. The only thing that may change is the base address of the peripheral, and/or some other attributes dynamically defined by register values (which is not expressible in SVD). If we could dynamically define the base address of the peripheral, the generated PAC could be shared across different SoCs that share the same peripheral. It would also allow writing a HAL to the peripheral, a driver, etc. The HAL for a SoC would then be composed of HALs for each of its peripherals. What do you think? Maybe there is a better place for this discussion? |
If you are saying about declarative macros that is what stm32ral exactly does. Also there is
How much simpler everything would be if this were true.
I don't mind it. |
I'll keep looking at I am thinking more of a macro that handles the boilerplate for accessing the wrapped inner
Right, I've considered using
Yeah... I opened an issue with the upstream Or, are you saying that peripherals on different SoCs are not interchangeable, even if they are based on the same IP (read same |
I can imaging only See https://github.com/burrbull/reg Other things like field/register readers and writers should be copied anyway. |
Split peripheral modules into crates
This proposal is to add a CLI option to split peripheral modules into separate crates in a project workspace.
Motivation
For large PAC crates, compilation on machines with less-powerful cores is excruciatingly slow. The bottleneck for any projects depending on the PAC crate is obviously the PAC, because one core is pinged to full usage, while all other cores are idle.
By splitting the PAC into separate crates for each peripheral, each core could work on a separate peripheral crate. The separate crates could also improve incremental compilation, since a change in one of the peripheral crates would not necessarily require recompilation of other peripheral crates.
Challenges
Much of the plumbing is already there for creating separate crates for each peripheral.
Each peripheral already generates its own module.
Peripheral versioning would inherit from the top-level
Cargo.toml
version.The main challenge will be making minimal changes to enable the code generation, without adding too much to maintainability burden.
Example
An example project structure might look like:
Alternative approaches
Once the parallel front-end is stable in
rustc
, the main motivation for this proposal may be less relevant.However, there will still be users stuck on older versions of
rustc
where this proposal will be useful.The text was updated successfully, but these errors were encountered: