Swift for bare-metal programming


(Rick M) #1

I'm not sure what effort is already underway to support this, but I'd like to be able to take advantage of Swift's inherent robustness to develop code for embedded devices without the benefit of an OS like Linux. I see at least two classes of such development: small and large embedded processors. "Large" ones typically have external DRAM and flash (think Beaglebone Black or Raspberry Pi), small ones have on-board DRAM and flash, and execute directly from flash. The smallest ones don't even have a RAM-based stack, and I'm not considering those. But there are a large number of small MCUs that can be programmed in C++, and it's those I'd like to eventually be able to target.

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"). 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.

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.

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.

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.

I'd eventually love to be able to write a real-time OS largely in Swift (with perhaps only startup code like the vector table and thread context switch code done in assembly).

Thanks!

···

--
Rick Mann
rmann@latencyzero.com


(Anton Zhilin) #2

I'm not sure what effort is already underway to support this, but I'd like
to be able to take advantage of Swift's inherent robustness to develop code
for embedded devices without the benefit of an OS like Linux. I see at
least two classes of such development: small and large embedded processors.
"Large" ones typically have external DRAM and flash (think Beaglebone Black
or Raspberry Pi), small ones have on-board DRAM and flash, and execute
directly from flash. The smallest ones don't even have a RAM-based stack,
and I'm not considering those. But there are a large number of small MCUs
that can be programmed in C++, and it's those I'd like to eventually be
able to target.

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.

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.

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.

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 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.

···

2016-08-16 23:07 GMT+03:00 Rick Mann via swift-evolution < swift-evolution@swift.org>:


(Rick M) #3

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).

Thanks!

···

On Aug 16, 2016, at 15:27 , Anton Zhilin <antonyzhilin@gmail.com> wrote:
2016-08-16 23:07 GMT+03:00 Rick Mann via swift-evolution <swift-evolution@swift.org>:

--
Rick Mann
rmann@latencyzero.com


(Anton Zhilin) #4

>> 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?

Yes, using UnsafeMutablePointer. But I'm not sure about padding.

> 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).

Ok, you should be able to use classes, etc. You just won't be able to
create new instances without heap allocation. Just as in C++. And for
"classes on stack", we've got struct types.

···

2016-08-17 3:27 GMT+03:00 Roderick Mann <rmann@latencyzero.com>:


(Charlie Monroe) #5

2016-08-17 3:27 GMT+03:00 Roderick Mann <rmann@latencyzero.com <mailto:rmann@latencyzero.com>>:
>> 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?

Yes, using UnsafeMutablePointer. But I'm not sure about padding.

AFAICT, there is no way to create a packed struct in Swift. I was thinking about making a proposal for it, but there are fairly easy workarounds:

http://stackoverflow.com/questions/24139149/how-do-i-create-a-packed-data-structure-in-swift

···

On Aug 17, 2016, at 2:47 AM, Anton Zhilin via swift-evolution <swift-evolution@swift.org> wrote:

> 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).

Ok, you should be able to use classes, etc. You just won't be able to create new instances without heap allocation. Just as in C++. And for "classes on stack", we've got struct types.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution