[swift-evolution] Swift for bare-metal programming
rmann at latencyzero.com
Tue Aug 16 19:27:28 CDT 2016
> On Aug 16, 2016, at 15:27 , Anton Zhilin <antonyzhilin at gmail.com> wrote:
> 2016-08-16 23:07 GMT+03:00 Rick Mann via swift-evolution <swift-evolution at swift.org>:
>> But to start, I'd like to be able to target the Beaglebone Black (TI Sitara AM335x ARM processor). On the swift-users list we talked about this a bit (Subject: "Swift in bare-metal embedded programming/Swift runtime").
> This itself is not a question of SE, but rather of implementation for these platforms. I guess, Apple engineers won't really want to do this work.
I only mention this platform specifically as an example to help illustrate what I'm hoping to be able to accomplish. On the low end of the spectrum, I'd love to be able to target an Atmel ATmega32.
>> Most of my initial questions centered on the Swift runtime and how bulky that might be, and about how to statically link a set of Swift files and the runtime into a monolithic block of code.
> `swiftc` already generates dependency-free executables.
Cool, I'll examine that a bit.
>> But then I remembered the need for something as basic as a "naked" function, one that could serve as an entry point for an interrupt vector. In GCC (and Clang, presumably), you can prepend "__attribute__ ((naked))" on a function declaration. You can then use those function names in the assembly file you build for the vector table.
> Agreed, something like `@export(demangledName)` would be useful.
I understand this to be a proposed mechanism for specifying the function name, but it also needs something like @naked to indicate that no prologue or epilogue should be generated for the function.
>> There's also the need to be able to name a specific physical (perhaps virtual) memory address and do bit operations on them. In C/C++, this is relatively easy. Not sure how one would do this in Swift.
> UnsafeBytes, UnsafePointer, UnsafeBufferPointer do this. Suddenly, interaction with C gets more verbose, but it is also verbose in many other "safe" languages.
In C on an Atmel MCU, it's done with macros:
#define _MMIO_BYTE(mem_addr) (*(volatile uint8_t *)(mem_addr))
#define DIDR1 _MMIO_BYTE(0x7F)
In code, you can then write:
DIDR1 = 0xXX;
And that writes that byte to address 0x7F.
In more sophisticated MCUs, a hardware peripheral will have several registers in memory, and they'll be defined by a struct in C. The base address of the struct is changed depending on which instance of the hardware peripheral you're talking about (i.e. there can be four USARTS, each with several bytes of configuration registers). Then the client code looks like (in C):
USART1->BAUD = ...;
USART1->CFG = ...;
USART1->TXDATA = ...;
Importantly, the struct members have no padding, and an instance of the struct is declared to exist at a specific memory address.
Can that be done in Swift?
> In a lot of embedded programming, one pre-allocates all memory so that the running program need not allocate and deallocate memory as it goes. This enhances reliability. It would be nice for Swift to support this, in that you'd want to be able to ensure the runtime isn't calling malloc when you don't want it to.
> We could create a list of malloc-free standard library entities. Then if you use only this subset of language, you'll be fine. Plus, no classes, closures, `indirect`, and existential protocols.
It would be a shame to have to lose all that. I can still use classes in C++, even on very small MCUs. Sometimes I disable RTTI and exception handling because they cause a lot of bloat. I avoid the STL in some cases for the same reason. Calling malloc() isn't bad, you just want to know when it's called, and do that in your app's initialization, and not during the run loop (whatever form your run loop takes).
rmann at latencyzero.com
More information about the swift-evolution