Accompanying Ole's great work on getting a pure Swift environment up and running on the Raspberry Pi Pico I've been working on implementing a hardware access layer for the RP2040.
The package is based on Swift MMIO. It provides access to all of the RP2040's peripherals and their registers. Overall it's about 35k lines of generated Swift source code.
I have not yet managed to compile actual RP2040 code. Currently there's still a bug that prevents macros from cross compiling correctly. But it is possible to write code against the module's API by compiling for macOS and setting up dummy register banks (see RP2040Playground).
A problem I have found is that the package needs ~11 minutes to compile. This is probably due to the amount of macros involved. Debug and release builds do not really differ in compile time.
This is fantastic! Having autogenerated Swift types for all peripherals is a great base for writing our own RP2040 SDK in pure Swift. I can't wait until we can bring this all together and run it on an actual RP2040.
Awesome work! You've kinda run ahead into another part of the project I was not yet planning on announcing/releasing, but I'd rather avoid duplicated work.
MMIO has a private branch containing svd2swift a code generation tool like you've written, which also integrates as a swift package build plugin. I'll try to make that public today/tomorrow and hopefully we can collaborate on that one implementation instead of maintaining two.
Yeah thats definitely way too long, but I think segmenting the compile time of swift-syntax out from the target build is useful to isolate the impact of macro expansion.
Note: I manually ran swiftc commands using a release variant of the MMIOMacros executable to bring the compile times way down.
I think swift build could get much much much faster with cross-package builds caching. This would dramatically improve the swift-syntax experience, see Cross package build caching · Issue #7234 · apple/swift-package-manager · GitHub. The main issue I see is resources, Max is doing an amazing job modernizing SPM but it's a big undertaking.
I have just pushed a branch expand-mmio-macros to the RP2040MMIO repo. In this branch all MMIO macros are pre-expanded (so the source does not contain any macros at all).
The previously 36637 lines of code are now 241402 (6,5× more). The compile time is reduced to 23 seconds (nearly 30× faster), though.
@ole Would be nice to do another precise comparison?
@rauhul: MMIO has […] svd2swift a code generation tool
This sounds terrific! Great to hear that you're seeing MMIO going in the same direction. I'm eager to explore what you have already done (and happy to throw away my toying around).
I've not yet found time to really dig into what you have posted but I'm definitely looking forward to do that. My code has a lot of deficiencies (like emitting peripherals multiple times instead of arrays).
Timing swift build (debug build) and swift build -c release (release build)
Ran swift package clean before each build
So not quite your 23 seconds, but a very substantial speedup, especially for clean debug builds. Interestingly, the nightly compiler was much slower this time, maybe because it has more assertions enabled?
The vast majority of the build time is still spent on building SwiftSyntax because it's a dependency of MMIO.
My takeaways:
It's not just the SwiftSyntax build time. When you have lots of macros, macro expansion itself is a major bottleneck (as @rauhul already hinted at above).
If SwiftPM were somehow able to figure out that (a) SwiftSyntax is only used by MMIO to provide macros and (b) the client code doesn't use any macros, it could potentially skip building SwiftSyntax altogether. I don't know how feasible this is, though. Figuring out (a) seems possible just by looking at the dependency graph, but figuring out (b) seems impossible without scanning all source files in all targets downstream of the .macro target.
Small update so folks dont think this work has stalled. I am waiting on some final approval to pull in a dependency of svd2mmio for testing, then I will open the PR for real and merge it. I'd love help improving the SVD coverage decoding logic if anything is missing.
For example the SVD module currently doesn't parse enumerated values which it definitely should.
I have also prototyped svd2lldb which is an lldb plugin that can be used to print registers by symbolic name (and more) directly in lldb. I would like to productionize this after svd2swift lands.
SVD2SwiftTests: a collection of snapshot tests to validate converting parsed SVD to swift source.
SVD2SwiftPlugin: a SwiftPM build tool to run svd2swift automatically at build time
SVD2SwiftPluginTests: a minimal test target to validate the plugin infrastructure doesn't entirely break
svd2lldb is definitely still coming, but I want get more of the svd2swift work done before merging it in. However, if anyone is interested in working on the lldb plugin, I'm happy to push a branch that you can build on top of.