Skip to content

Repository files navigation

stubforth

A small, C-based, indirect threaded forth system intended to run on bare metal.

[[file:stubforth.jpg]]

* Goals
- 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

* Design
** C Extensions used
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
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
: )

** Standard conformance
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 of =create=.
- Throwing a 0 does non-local control flow without rolling back the parameter stack.
- No automatic "OK" response
- Outlandish operator names.  E.g., =<<= instead of =lshift=.  This
  matters when squeezing stubforth into smaller µCs.

* Source
** Repository
https://github.com/anse1/stubforth

See the file COPYING for warranty and redistribution conditions.

** Branches
Platform-specific code resides on individual branches to avoid
littering the code with conditional compilation.

*** =master=
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.

*** =posix=
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.

*** =m68k/dragonball=
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.

*** =arm/cortexm=
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.

***** =arm/launchpad=
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.

***** =arm/stm32=
Targets the STM32F4-Discovery board.  Uses USART2 for I/O.

*** =x86_64/linux=
Targets the Linux kernel by using syscalls instead of libc for I/O.  A
=syscall= primary is provided.

*** =sh3/lancom=
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.

*** =msp430/g25=
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.

* Bugs
** TODO Make use of GCC's Named Address Spaces to support Harvard architectures.
An ATMega8 ought to be a feasible target.
** TODO Allow dictionaries in persistent store.
Currently, persistence of non-static words is achieved by storing
Forth source in Flash and compiling them on startup.
** TODO Init some of the C runtime using C code.
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...

** TODO Factor terminal code out into baremetal branch
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.

** TODO Figure out more general way to put source code into flash
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.

About

A small, C-based, indirect threaded forth system intended to run on bare metal

Resources

Stars

10 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages