muforth is a small, simple, fast, indirect-threaded code (ITC) Forth intended for use as a cross-compiler for microcontrollers and other embedded devices. It is written in C and its core is very portable. Because of its Forth nature, it is naturally extensible, scriptable, and customizable.
Unlike mecrisp – which could be considered muforth’s main “competition” – muforth supports a tethered development model, where the dictionary names and all the interactive command processing live on the host, and only the code and data live on the target machine. This makes it possible to target very small devices with a few kilobytes of flash. In contrast, mecrisp needs at least 16 KiB of flash to be useful; 32 KiB is a more comfortable minimum. On the other hand, mecrisp is very polished and useful, while muforth is still a work-in-progress. ;-)
muforth is very well-suited to interactive coding, debugging, and exploration, and is a great tool for bringing up new hardware.
It has support – in varying degrees of completeness – for a number of different architectures and chip families.
- ARMv6-m (aka Cortex-M0/M0+)
- ARMv7-m (aka Cortex-M3/M4)
- MSP430 (TI)
- RISC-V (currently the SiFive FE310 and GigaDevice GD32VF103)
- ARMv5 (originally targeting an ARM AEB-1 board running an ARM7DI processor)
- AVR (Atmel)
- HC08 and HCS08 (Motorola/Freescale/NXP)
- PIC18 (Microchip)
I initially wrote muforth because I wanted to try out some implementation ideas. Today there is very little that distinguishes muforth from fig-FORTH – but the differences go rather deep.
Its implementation is no longer the point. Its sole reason for existing is to be a cross/meta/target-compiler for other Forths, and their implementations are in no way tied to muforth’s. In fact, muforth can be used to compile any sort of code onto the target. I’ve used it very successfully as a smart assembler for writing AVR and S08 code.
The code – both the C code that implements the Forth virtual machine and the muforth code that does everything else – is carefully and in some cases extensively (even obsessively!) commented. Right now your best source of documentation is the code! Luckily for you, there isn’t that much, so reading it is actually possible. That’s part of the point of muforth; I want it to be a convivial tool.
The key to the system is the Forth code that muforth reads when it first starts: startup.mu4. You’ll learn a lot by reading this!
Look in mu/target/ to find a target that interests you. There is generally a mu/target/<target>/build.mu4 that loads the cross-build environment. Use it as an “index” to find the assembler, disassembler, meta-compiler, kernel, and other key pieces of code.
The index of all pages is also a place to look. I’m planning to write a nice manual for the overall system and “getting started” guides for each of the targets.
NOTE: The state of muforth’s documentation will get much better! Especially if I hear feedback about how terrible it is. ;-)
For breaking news, follow @muforth.
The muforth blog is made up of yearly journal pages. Read them here:
- 2021 journal
- 2020 journal
- 2018 journal
- 2017 journal
- 2016 journal
- 2015 journal
- 2014 journal
- 2013 journal
- 2010 journal
- 2009 journal
- 2008 journal
The original README – though outdated in many ways – is a good introduction to why I wrote muforth and what I was trying to achieve. It describes the native-code compiler version of the system. That, and a few other things – notably create/does, the tokeniser, and the lack of tail-recursion in the threaded version – have changed since the README was written, but much of it is still true, applicable, and hopefully of interest.
Warning: I wave my arms around a lot, and the audio and video quality isn’t that great, but you might find it interesting, or at least amusing.
It’s also hard to see my slides. If you want to “follow along”, download my slides, and use
less to view them – ideally in a text window that is about 31 lines high – like so:
less -G 2008-mar-30-PNCA
/^=== to get to the second page, and
n to page forward after that.