> Since the Internet seems to be full of people with way too much time on their hands, I would just like to kindly shoo away any C/C++ pedants out there. Yes, I am sure there are a million different ways to achieve many of the same results. Yes, I am sure there are some fine points of language semantics that could be argued about. Yes, I am sure you have a more efficient way of writing some of the functions.
You really shouldn't, Gary is extremely pedantic himself. He really really dislikes criticism or being corrected. For example on youtube, in many of his video comment's, he's engaged in long fights with anyone who claims that Arduino code is C++. In his mind it isn't, therefore that's that.
>Piccolo OS [...] is designed primarily as a teaching tool.
This means you must carefully balance teaching the right thing (a realistic system implemented skillfully) against teaching the right way (simplification for didactic purposes).
You shouldn't. This is what hardware people always say, and then when the result is an unmaintainable mess, they want software people to bail them out.
It's a totally fine and respectable boundary to have: "I'm going to share some stuff I did for free for other people to learn from, but not if I get a bunch of bitchy/pedantic notifications about it."
I remember Linux (and NetBSD) running on outrageously low-end hardware (even hardware without an MMU). While modern Linux is a no-go, would there any existing and relatively popular OS be viable?
You can run uC Linux without an MMU, but you won't get memory safety. Better microcontrollers (that includes the RP2040 and RP2350) have an MPU (memory protection unit) to implement memory safety, but almost no microcontroller has a real MMU (only the MIPS derived PIC32 come to mind). An MPU is far more visibly exposed to the programmer than a paging MMU that combines access control with address space virtualisation. To make it even more annoying the ARMv6M architecture isn't intended to recover from memory usage faults. You have to use really dirty tricks to "fake it" (return from the hard fault into an unimplemented exception, infer the address and cause the fault before you can recover), but it's possible. It's not even that slow. Depending on your usecase a fast warm-start of the whole chip may be preferable to restarting single tasks (e.g. just set the hardware watchdog countdown timer to 1 and spin until it happens).
I wouldn’t say RISC-OS or EmuTOS would be sensible options for new development unless the point is to develop for them (I wrote a couple programs to use Tektronix 4014 graphics the other day in order to use Tektronix 4014 graphics). I was thinking about reusing existing OSs and their stacks.
I used to work with a Cortex-M3 port of uCLinux, but it was kind of a pain to manage. The biggest problem being every executable had to be statically linked to all of its dependencies.
In short: it's a toy OS built primarily for teaching, and it's a cooperative multitasking OS, without process isolation. So it's more like Node.js (or win16, or macOS classic) than like what we usually call an OS.
That’s a weird comment. Node.js is a stack that works on top of an OS. If you could just plop it on a SD card and boot a computer with it, it would be a OS. Things like DOS or MacOS 9 were definitely operating systems. There is no reason to restrict the term to those with preemptive multitasking.
"OS" in this context means "scheduler", i.e the code that coordinates your application tasks.
That description can also apply to VMs such as JS, hence the comparison.
You could consider this type of library OS even more tightly bound to the application than your typical JS app as its actually linked to the user code.
"Operating Systems" for microcontrollers such as this are frequently just schedulers as the Application typically contains drivers and hits the hardware itself. e.g. FreeRTOS.
Even those implement communication primitives e.g. locks, semaphores, mailboxes, etc. as part of the OS. Some of the larger ones also define a driver model of sorts (which often just codifies the structure of the first driver for that type of peripheral e.g. USB, Ethernet, CAN, I2C, SPI, GPIO).
> "OS" in this context means "scheduler", i.e the code that coordinates your application tasks
If you define the context to mean it and then assume that everyone agrees with your implicit context, then maybe. In reality, OS and schedulers are not the same thing.
It’s also a leap from the “MacOS 9 was not an OS” GP position.
Then surely there are instances of people saying that it is “not an OS”. And I don’t mean hyperbole.
Here are 3 definitions from 3 different sources: https://www.wordnik.com/words/operating%20system . Not a single one even mentions process scheduling or anything to exclude MULTICS, CP/M, DOS, or any version of MacOS or Windows. I know that some people think that being contrarian on HN is cool, but this is beyond ridiculous.
And the scheduler decides which thread gets to run next. On a cooperative multitasking system, guess what the OS code you jump to when you yield from a thread does, and what it's called?
The RP2040 has a single QSPI controller channel, but with clever hacks you can multiplex that to boot from SPI and switch over to some other (Q)SPI peripheral, but iirc you can't write directly (can be emulated via MPU+DMA). What's also quite neat is that you can use the external flash cache as 16kiB SRAM tiled repeatedly over a 16MiB memory window. By abusing the MPU you can allow/trap accesses down to 256 byte granularity and implement virtual memory (allow only one alias address at a time, treat the 16kiB SRAM as a direct mapped cache, and demand page from QSPI, other SRAM banks, or whatever you can come up with).
Impressive work! Of course you can access external RAM, but it comes with some compromises re: speed and usability. Other ARM microcontrollers have a full SDRAM controller on board in its normal address space with very little overhead compared to the internal memory. I'd imagine the SPI RAM here is an order of magnitude slower than the internal RAM, if not two?
edit - that is one WILD codebase... it has both pi pico support but also (remnants of)... Mac OS 9 support!? `#ifdef __MWERKS__`??
Oh, yes, it's a crazy project overall. I would love to see it continue -- I think the Transputer and its OS HeliOS, which is FOSS now -- still has much to teach. But he got it working, so I can also see why not stop digging if you hit the bottom.
Well the RP2040 has a QSPI controller but it has only a single channel that is normally the "boot device". If you bootstrap via SWD (or USB) this device could be at least a QSPI RAM, but writes would have to trapped and implemented in the HardFault handler which is of course very slow compared to internal SRAM. The RP2350 adds a second QSPI channel with QSPI bus (just an additional chip select pin).
TBH I don't know the details of how it works. I am not at all an electronics person. But did you read the article? All I'm saying is that it is possible to add more RAM to a Pi Pico. That, to me, seems to falsify the statement that it can't.
We like to conceptualise OSes as programs, but at the low end they start to resemble libraries.
if your FS is just a library, process switching is timers and interrupts, and memory protection is provided by the processor, what is the OS? Where is the OS?
It would be interesting to run each task (likely in simulation), measure the stack size they need, and pre-allocate. That would alleviate the downside of giving each task a stack a lot.
Worth reminding that lots of tasks don't need their own stack, so detecting (or hinting) that would be extremely worthwhile.
> Since the Internet seems to be full of people with way too much time on their hands, I would just like to kindly shoo away any C/C++ pedants out there. Yes, I am sure there are a million different ways to achieve many of the same results. Yes, I am sure there are some fine points of language semantics that could be argued about. Yes, I am sure you have a more efficient way of writing some of the functions.
> To be honest, I am not interested.
I respect this so much.
> I respect this so much.
You really shouldn't, Gary is extremely pedantic himself. He really really dislikes criticism or being corrected. For example on youtube, in many of his video comment's, he's engaged in long fights with anyone who claims that Arduino code is C++. In his mind it isn't, therefore that's that.
I have found him to say some incorrect stuff and being extremely reluctant to even reflect on it.
I dislike him quite a lot to be honest...
>Piccolo OS [...] is designed primarily as a teaching tool.
This means you must carefully balance teaching the right thing (a realistic system implemented skillfully) against teaching the right way (simplification for didactic purposes).
You shouldn't. This is what hardware people always say, and then when the result is an unmaintainable mess, they want software people to bail them out.
It's a totally fine and respectable boundary to have: "I'm going to share some stuff I did for free for other people to learn from, but not if I get a bunch of bitchy/pedantic notifications about it."
that said, there's not really a lot here, so I'm not sure what anyone would take issue with
TIL and looked it up, typedef is indeed just a specifier like any other in a declaration.
Aren't those the same thing? <type> typedef <name>
My c is pretty rusty, admittedly.
The interesting thing being pointed out is that you can do both `typedef <type> <name>;` (the common way, I think) and `<type> typedef <name>;`.
for a less toy example, it seems like FreeRTOS can be used also on the Rpi pico: https://freertos.org/Documentation/02-Kernel/03-Supported-de...
I remember Linux (and NetBSD) running on outrageously low-end hardware (even hardware without an MMU). While modern Linux is a no-go, would there any existing and relatively popular OS be viable?
You can run uC Linux without an MMU, but you won't get memory safety. Better microcontrollers (that includes the RP2040 and RP2350) have an MPU (memory protection unit) to implement memory safety, but almost no microcontroller has a real MMU (only the MIPS derived PIC32 come to mind). An MPU is far more visibly exposed to the programmer than a paging MMU that combines access control with address space virtualisation. To make it even more annoying the ARMv6M architecture isn't intended to recover from memory usage faults. You have to use really dirty tricks to "fake it" (return from the hard fault into an unimplemented exception, infer the address and cause the fault before you can recover), but it's possible. It's not even that slow. Depending on your usecase a fast warm-start of the whole chip may be preferable to restarting single tasks (e.g. just set the hardware watchdog countdown timer to 1 and spin until it happens).
Guess it depends on your definition of popular. There's various RTOS products, some of which have POSIX APIs.
If you're fine with obscure and retro, there's things like RISC-OS (ARM). Or EmuTOS (68k/ColdFire). Or FreeDOS etc (x86)
I wouldn’t say RISC-OS or EmuTOS would be sensible options for new development unless the point is to develop for them (I wrote a couple programs to use Tektronix 4014 graphics the other day in order to use Tektronix 4014 graphics). I was thinking about reusing existing OSs and their stacks.
You can run modern Linux without an MMU! But other popular embedded OSes I've heard about are FreeRTOS and Zephyr.
And someone has in fact managed to get MMU-less Linux running on the newer Pico 2:
https://github.com/Mr-Bossman/pi-pico2-linux
That's with an 8MB external PSRAM though, fitting modern Linux in the internal SRAM is probably a step too far.
I used to work with a Cortex-M3 port of uCLinux, but it was kind of a pain to manage. The biggest problem being every executable had to be statically linked to all of its dependencies.
I've been using protothreads on the RP2040 (Pico MCU) for task management.
https://dunkels.com/adam/pt/
The extensions available from Hunter Adams at Cornell are also very useful. In particular, PT_YIELD_INTERVAL() has been very useful for me.
https://people.ece.cornell.edu/land/courses/ece4760/RP2040/C...
In short: it's a toy OS built primarily for teaching, and it's a cooperative multitasking OS, without process isolation. So it's more like Node.js (or win16, or macOS classic) than like what we usually call an OS.
That’s a weird comment. Node.js is a stack that works on top of an OS. If you could just plop it on a SD card and boot a computer with it, it would be a OS. Things like DOS or MacOS 9 were definitely operating systems. There is no reason to restrict the term to those with preemptive multitasking.
"OS" in this context means "scheduler", i.e the code that coordinates your application tasks. That description can also apply to VMs such as JS, hence the comparison.
You could consider this type of library OS even more tightly bound to the application than your typical JS app as its actually linked to the user code.
A scheduler is part of a OS, but a scheduler alone does not make a OS.
"Operating Systems" for microcontrollers such as this are frequently just schedulers as the Application typically contains drivers and hits the hardware itself. e.g. FreeRTOS.
Even those implement communication primitives e.g. locks, semaphores, mailboxes, etc. as part of the OS. Some of the larger ones also define a driver model of sorts (which often just codifies the structure of the first driver for that type of peripheral e.g. USB, Ethernet, CAN, I2C, SPI, GPIO).
> "OS" in this context means "scheduler", i.e the code that coordinates your application tasks
If you define the context to mean it and then assume that everyone agrees with your implicit context, then maybe. In reality, OS and schedulers are not the same thing.
It’s also a leap from the “MacOS 9 was not an OS” GP position.
> It’s also a leap from the “MacOS 9 was not an OS” GP position.
That wouldn't be the first time I've heard that statement, even among classic Mac enthusiasts.
Then surely there are instances of people saying that it is “not an OS”. And I don’t mean hyperbole.
Here are 3 definitions from 3 different sources: https://www.wordnik.com/words/operating%20system . Not a single one even mentions process scheduling or anything to exclude MULTICS, CP/M, DOS, or any version of MacOS or Windows. I know that some people think that being contrarian on HN is cool, but this is beyond ridiculous.
And the scheduler decides which thread gets to run next. On a cooperative multitasking system, guess what the OS code you jump to when you yield from a thread does, and what it's called?
That was my point.
replied to the wrong coment, sorry
> "OS" in this context means "scheduler",
That's essentially what OS is: some bootstrap, scheduler and some APIs for developers and some drivers.
What context are we talking about here?
It’s also running on a microcontroller with a few hundred kb of memory so even win16 or macOS classic would be a bit heavy.
> so even win16 or macOS classic would be a bit heavy.
Speed-wise, both would run exceptionally well on that hardware.
The first Mac had 128kB memory, about 32 of which were taken by its video and audio buffers. It ran at about 8MHz.
The first version of Windows ran on similar hardware, requiring a 8088 and 256kB of memory.
The pico has at least that amount of memory, at top speed 16 times the clock frequency, and two cores.
https://axio.ms/projects/2024/06/16/MicroMac.html
The Pico doesn't have an external memory bus, but something like MacOS Classic for an STM32 with a chunk of SDRAM and VGAish video would be fun.
The Pico 1 (i.e. the RP2040) doesn't. The Pico 2 (RP2350) does, albeit a fair bit slower (since it's QSPI PSRAM) than the internal SRAM.
The RP2040 has a single QSPI controller channel, but with clever hacks you can multiplex that to boot from SPI and switch over to some other (Q)SPI peripheral, but iirc you can't write directly (can be emulated via MPU+DMA). What's also quite neat is that you can use the external flash cache as 16kiB SRAM tiled repeatedly over a 16MiB memory window. By abusing the MPU you can allow/trap accesses down to 256 byte granularity and implement virtual memory (allow only one alias address at a time, treat the 16kiB SRAM as a direct mapped cache, and demand page from QSPI, other SRAM banks, or whatever you can come up with).
> The Pico doesn't have an external memory bus
I may be misunderstanding what you are saying here but if I read this correctly, you are wrong.
The project to run Transputer code on the Pi Pico uses a memory expansion for the original Pi Pico. I described it here:
https://www.theregister.com/2022/05/06/pi_pico_transputer_co...
Impressive work! Of course you can access external RAM, but it comes with some compromises re: speed and usability. Other ARM microcontrollers have a full SDRAM controller on board in its normal address space with very little overhead compared to the internal memory. I'd imagine the SPI RAM here is an order of magnitude slower than the internal RAM, if not two?
edit - that is one WILD codebase... it has both pi pico support but also (remnants of)... Mac OS 9 support!? `#ifdef __MWERKS__`??
Oh, yes, it's a crazy project overall. I would love to see it continue -- I think the Transputer and its OS HeliOS, which is FOSS now -- still has much to teach. But he got it working, so I can also see why not stop digging if you hit the bottom.
P.S. I wrote about HeliOS too:
https://www.theregister.com/2021/12/06/heliosng/
Well the RP2040 has a QSPI controller but it has only a single channel that is normally the "boot device". If you bootstrap via SWD (or USB) this device could be at least a QSPI RAM, but writes would have to trapped and implemented in the HardFault handler which is of course very slow compared to internal SRAM. The RP2350 adds a second QSPI channel with QSPI bus (just an additional chip select pin).
TBH I don't know the details of how it works. I am not at all an electronics person. But did you read the article? All I'm saying is that it is possible to add more RAM to a Pi Pico. That, to me, seems to falsify the statement that it can't.
Not everything needs to run directly from RAM.
By your definition, CP/M and DOS are not operating systems either
I don't think that makes the definition wrong.
We like to conceptualise OSes as programs, but at the low end they start to resemble libraries.
if your FS is just a library, process switching is timers and interrupts, and memory protection is provided by the processor, what is the OS? Where is the OS?
It would be interesting to run each task (likely in simulation), measure the stack size they need, and pre-allocate. That would alleviate the downside of giving each task a stack a lot.
Worth reminding that lots of tasks don't need their own stack, so detecting (or hinting) that would be extremely worthwhile.
Fuzix works as well... https://www.reddit.com/r/raspberrypipico/comments/15si3ow/fu...
This is cool! works well as a way of understanding how to get an OS going on Pico