theandrew168 / derzforth

Bare-metal Forth implementation for RISC-V
MIT License
42 stars 5 forks source link
bare-metal forth longan-nano risc-v wio-lite

DerzForth

Bare-metal Forth implementation for RISC-V RV32I core.

About

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.

Requirements

The hardware requirements for running DerzForth are minimal and straightforward:

DerzForth has been tested on the following RISC-V development boards:

Setup

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

Boards

Some boards require a USB to UART cable in order to program and/or interact. I recommend the CP2012.

Longan Nano [Lite]

For this board, the only setup necessary is a USB to UART cable.

Wio Lite

For this board, the only setup necessary is a USB to UART cable.

GD32 Dev Board

For this board, the only setup necessary is a USB to UART cable.

HiFive1 Rev B

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.

Build

With Bronzebeard installed:

bronzebeard -c -i boards/<target_board>/ --include-definitions derzforth.asm

Program

Some boards share a common method of programming and interacting.

GD32VF103 Boards

Enable boot mode on your given device:

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

FE310-G002 Boards

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

Execute

GD32VF103 Boards

After programming, put the device back into normal mode:

FE310-G002 Boards

The J-Link command from the previous step will automatically reset the chip after programming!

Interact

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

Primitive Words

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