Bare-metal Forth implementation for RISC-V RV32I core.
Forth was initially designed and created by Charles Moore. Many folks have adapted its ideas and principles to solve their own problems. Moving Forth by Brad Rodriguez is an amazing source of Forth implementation details and tradeoffs. If you are looking for some introductory content surrounding the Forth language in general, I recommend the book Starting Forth by Leo Brodie.
This implementation's general structure is based on Sectorforth by Cesar Blum. He took inspiration from a 1996 Usenet thread wherein folks discussed requirements for a minimal yet fully functional Forth implementation.
The hardware requirements for running DerzForth are minimal and straightforward:
- At least 16KB of RAM (define
RAM_BASE_ADDR
andRAM_SIZE
) - At least 16KB of ROM (define
ROM_BASE_ADDR
andROM_SIZE
) - Serial UART (implement
serial_init
,serial_getc
, andserial_putc
)
DerzForth has been tested on the following RISC-V development boards:
If you are unfamiliar with virtual environments, I suggest taking a brief moment to learn about them and set one up. The Python docs provide a great tutorial for getting started with virtual environments and packages.
DerzForth is an assembly program based on the Bronzebeard project. Consult Bronzebeard's project page for how to get it all setup (it's pretty easy and works on all major platforms).
Bronzebeard (and a few other tools) can be installed via pip:
pip install -r requirements.txt
Some boards require a USB to UART cable in order to program and/or interact. I recommend the CP2012.
For this board, the only setup necessary is a USB to UART cable.
- Attach TX to pin R0 (PA10)
- Attach RX to pin T0 (PA9)
- Attach GND to pin GND
- Attach 3.3V to pin 3V3 (be sure not to supply 5V to 3.3V or vice versa)
For this board, the only setup necessary is a USB to UART cable.
- Attach TX to pin PA10
- Attach RX to pin PA9
- Attach GND to GND
- Attach 3.3V to 3V3 (be sure not to supply 5V to 3.3V or vice versa)
For this board, the only setup necessary is a USB to UART cable.
- Attach TX to pin RXD (PA10)
- Attach RX to pin TXD (PA9)
- Attach GND to GND
- Attach 3.3V to 3V3 (be sure not to supply 5V to 3.3V or vice versa)
Programming this board requires Segger's J-Link software. These tools work on all major platforms but depend on Java.
As far as cables go, just a single USB to Micro-USB cable is necessary.
- Plug the Micro-USB cable into the Micro-USB port
With Bronzebeard installed:
bronzebeard -c -i boards/<target_board>/ --include-definitions derzforth.asm
Some boards share a common method of programming and interacting.
Enable boot mode on your given device:
- Longan Nano - press BOOT, press RESET, release RESET, release BOOT
- Wio Lite - flip BOOT switch to 1, press and release RESET
- GD32 Dev Board - swap BOOT0 jumper to 3V3, press and release RESET, swap BOOT0 jumper to GND
To get a list of available serial ports, run the following command:
python3 -m serial.tools.list_ports
Then, program the device over serial UART:
stm32loader -p <device_port> -ewv bb.out
Here are some examples:
# Windows
stm32loader -p COM3 -ewv bb.out
# macOS
stm32loader -p /dev/cu.usbserial-0001 -ewv bb.out
# Linux
stm32loader -p /dev/ttyUSB0 -ewv bb.out
After converting the output binary to Intel HEX format, Segger J-Link handles the rest:
bin2hex.py --offset 0x20010000 bb.out bb.hex
JLinkExe -device FE310 -if JTAG -speed 4000 -jtagconf -1,-1 -autoconnect 1 scripts/hifive1_rev_b.jlink
After programming, put the device back into normal mode:
- Longan Nano - press and release RESET
- Wio Lite - flip BOOT switch to 0, press and release RESET
- GD32 Dev Board - TODO how does this board work?
The J-Link command from the previous step will automatically reset the chip after programming!
To interact with the device, the same port as above can used with pySerial's builtin terminal:
python3 -m serial.tools.miniterm <device_port> 115200
Here are some examples:
# Windows
python3 -m serial.tools.miniterm COM3 115200
# macOS
python3 -m serial.tools.miniterm /dev/cu.usbserial-0001 115200
# macOS (J-Link Serial over USB)
python3 -m serial.tools.miniterm /dev/cu.usbmodem0009790147671 115200
# Linux
python3 -m serial.tools.miniterm /dev/ttyUSB0 115200
This minimal selection of primitive words is used to bootstrap the Forth system.
Word | Stack Effects | Description |
---|---|---|
: |
( -- ) | Start the definition of a new secondary word |
; |
( -- ) | Finish the definition of a new secondary word |
@ |
( addr -- x ) | Fetch memory contents at addr |
! |
( x addr -- ) | Store x at addr |
sp@ |
( -- sp ) | Get pointer to top of data stack |
rp@ |
( -- rp ) | Get pointer to top of return stack |
0= |
( x -- flag ) | -1 if top of stack is 0, 0 otherwise |
+ |
( x y -- z ) | Sum the two numbers at the top of the stack |
nand |
( x y -- z ) | NAND the two numbers at the top of the stack |
key |
( -- x ) | Read ASCII character from serial input |
emit |
( x -- ) | Write ASCII character to serial output |