Reusing Bare Metal code for the Teensy 4.1 Inferno Port

Since all the previous work was done using a custom low-level language for bare metal coding, it needed to be done again in C for Inferno. This is slightly laborious, but ultimately quite useful because it requires a bit of thought and attention to redo it in C.

First steps

After trying to import a more-or-less complete set of files from the Apollo3 port and failing to make progress, I stripped the main function and l.s files back to something smaller, just to get the status LED to blink. Then it was a case of configuring the UART so basic debugging could be done.

To start with, the UART didn't work properly. Output was garbled. Some quick checking of my code showed that I hadn't called the code I imported to enable and configure the peripheral clocks. With that done, the UART could be used to print useful diagnostic information.

Putting things back in place

I put the code I removed back in and tried running the kernel again. This time problems arose as a result of the use of exception priorities and the BASEPRI register that can be used to mask exceptions with certain priority levels. For some reason that I need to investigate, trying to modify either this register or the CONTROL register seems to result in a usage fault with an undefined instruction error. This is despite the CONTROL register having a value of zero indicating, among other things, that the processor is in privileged mode.

Some messing around with system calls then occurred, which failed to lead to a solution to the problem of how to set these registers. In the end, I went back to using the PRIMASK register to enable and disable interrupts, using the CPS instruction. I don't think this is a good solution because I believe it can lead to lock loops in the test-and-set code.

Surprisingly, switching the mechanism behind spllo and friends made the kernel just work. I had expected other problems to arise before that happened.

Running programs

As with the other ports, there's nothing very fancy to see when Inferno runs:

Initial Dis: "/osinit.dis"
** Inferno
** Vita Nuova
teensy41mm$ blink &
teensy41mm$ cat /dev/memory
      75168      260057       76064         823         290          44      184877 main
      20416      212774       20416         186          47          13      192346 heap
          0           0           0           0           0           0           0 image
teensy41mm$ ps
       1        1    inferno    0:00.0    release    12K Sh[$Sys]
       3        2    inferno    0:00.0    release    12K Blink[$Sys]
       5        1    inferno    0:00.0      ready    13K Ps[$Sys]

As you can see, there's around 460K of free RAM to play with, which is more RAM than the Cortex-M4 ports have to start with. There's also another 512K on the chip which I need to enable somehow.

David Boddie
4 November 2023