stubforth
A small, C-based, indirect threaded forth system intended to run on bare metal.
- Portability
- readily portable to anything GCC targets
- Maintainability
- testsuite included
- C integration
- zero-terminated forth strings, reentrant VM, FFI
- Size
- about 10kB for a 32-bit build
Using C extensions contradicts the goal of ultimate portability, but some of them are too good to pass up and support for them is common in other compilers than GCC (such as Libfirm/cparser and LLVM/clang). The following extensions are currently used:
- Labels as Values
- Instantly puts you inside the ballpark of the fastest C-Forths out there.
- Named initializers
- Allows robust filling of static C structs with macros.
- Inline assembly
- We’re targeting bare metal here…
__alignof__
- The compiler already knows the alignment requirements of the target. Doing it by hand would be error-prone and redundant work
M4 is used to hide the boring aspects of constructing Forth words as static C structs. Here are some examples of how definitions of Forth words look like in stubforth’s source before M4 expands them to code and static structs in plain C:
primary(min) sp--; if (sp[0].i < sp[-1].i) sp[-1] = sp[0]; secondary(if,, .immediate=1, LIT, ZBRANCH, COMMA, HERE, ZERO, COMMA )
I try to follow the standards unless doing so would violate the goals or not make sense to me or I didn’t find the time to coerce the code to conform yet. Patches welcome.
Some grave departures:
- Most words that return an error flag in the standard throw an exception instead.
- No counted strings.
- Use of
does>
with<builds
instead ofcreate
. - Throwing a 0 does non-local control flow without rolling back the parameter stack.
- No automatic “OK” response
- Outlandish operator names. E.g.,
<<
instead oflshift
. This matters when squeezing stubforth into smaller µCs.
https://github.com/anse1/stubforth
See the file COPYING for warranty and redistribution conditions.
Platform-specific code resides on individual branches to avoid littering the code with conditional compilation.
This branch contains the least specialized code. It expects a hosted C environment and uses getchar() and putchar() from libc for I/O. This is the branch new platform-independent features are added and to start porting to new platforms from.
Makes stubforth a nicer citizen on POSIX systems. mmap
is used to
provide a persistent dictionary, dlopen
is available to forth code
to allow FFI-access to the C world. For scripting convenience, #!
is
an alias to \
and command line arguments are available to forth
code.
An example to query PostgreSQL from forth using libpq via FFI is included.
Targets MC68EZ328 Palm-Like hardware. Includes code to use the builtin LCD controller, BBADS7843 touchscreen controller and write to te28f160 flash. Uses builtin UART for I/O. Interrupt handlers can be written in Forth. Also includes some forth code to zoom the mandelbrot set.
This branch is used to collect vendor independent code to support Cortex M chips, such as NVIC setup or startup code that is merged down into the following silicon vendor branches.
Targets TI’s Stellaris Launchpad. Uses the Launchpad’s USB-CDC-UART bridge for I/O. Note that an ascii 3 is interpreted as a line break on this port, as the bridge doesn’t pass out-of-band line breaks.
Targets the STM32F4-Discovery board. Uses USART2 for I/O.
Targets the Linux kernel by using syscalls instead of libc for I/O. A
syscall
primary is provided.
Runs on a “ELSA LANCOM DSL/I-10 Office” router with Hitachi’s SH3.
Uses the original bootloader on the Platform which can be activated by bridging J1. Builds an UPX file that can be uploaded w/ the original firmware updater.
Except the memory-mapped LEDs, no hardware support besides the UART.
Compiles for a msp430g2553 shipped with the later TI Launchpads. Due to RAM constraints, compiling new words is very limited though, and the “put source into flash” method of creating persistent words is not applicable here.
An ATMega8 ought to be a feasible target.
Currently, persistence of non-static words is achieved by storing Forth source in Flash and compiling them on startup.
Part of the C runtime environment can be initialized from C itself, such as BSS initialization, copying data from ROM, etc. Currently, everything before main is done in assembly on the platform branches.
Update: sh/lancom does some of the initialization in C. How to generalize…
Currently, buffering and raw/cooked/echo/noecho is duplicated in the
platform branches. master
isn’t the right place, as these are not
useful in a hosted environment.
Some targets (arm, sh3) use objcopy w/ target-specific options to turn source code into an ELF file that exposes a symbol to C code.
Others (m86k) put them into special flash blocks.