Skip to content

anse1/stubforth

Repository files navigation

stubforth

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

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

Make use of GCC’s Named Address Spaces to support Harvard architectures.

An ATMega8 ought to be a feasible target.

Allow dictionaries in persistent store.

Currently, persistence of non-static words is achieved by storing Forth source in Flash and compiling them on startup.

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…

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.

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

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published