Implemented Forth Words
My4TH tries to follow the Forth 2012 standard.
Here is an overview of all the Forth words implemented in the EPROM.
(Please note that My4TH XS and My4TH light have a different word list.)
! 2* ALIGN DROP LOOP SPACE
# 2/ ALIGNED DUP LSHIFT SPACES
#> 2@ ALLOT ELSE M* STATE
#S 2DROP AND EMIT MAX SWAP
' 2DUP BASE ENVIRONMENT? MIN THEN
( 2OVER BEGIN EVALUATE MOD TYPE
* 2SWAP BL EXECUTE MOVE U.
*/ : C! EXIT NEGATE U<
*/MOD ; C, FILL OR UM*
+ < C@ FIND OVER UM/MOD
+! <# CELL+ FM/MOD POSTPONE UNLOOP
+LOOP = CELLS HERE QUIT UNTIL
, > CHAR HOLD R> VARIABLE
- >BODY CHAR+ I R@ WHILE
. >IN CHARS IF RECURSE WORD
." >NUMBER CONSTANT IMMEDIATE REPEAT XOR
/ >R COUNT INVERT ROT [
/MOD ?DUP CR J RSHIFT [']
0< @ CREATE K S" [CHAR]
0= ABORT DECIMAL KEY S>D ]
1+ ABORT" DEPTH L SIGN
1- ABS DO LEAVE SM/REM
2! ACCEPT DOES> LITERAL SOURCE
Core Extension Words
.( <> DEFER HOLDS PICK U.R
.R ?DO DEFER! IS REFILL U>
0<> ACTION-OF DEFER@ MARKER ROLL UNUSED
0> AGAIN ENDCASE NIP S\" VALUE
2>R BUFFER: ENDOF OF SOURCE-ID WITHIN
2R> C" ERASE PAD TO [COMPILE]
2R@ CASE FALSE PARSE TRUE \
:NONAME COMPILE, HEX PARSE-NAME TUCK
BLK BUFFER FLUSH LOAD SAVE-BUFFERS THRU
BLOCK EMPTY-BUFFERS LIST REFILL SCR UPDATE
2CONSTANT 2VARIABLE D.R D2/ DABS DU<
2LITERAL D+ D0< D< DMAX M*/
2ROT D- D0= D= DMIN M+
2VALUE D. D2* D>S DNEGATE
? BOUNDS KEY? RDROP >=
.S DUMP MS -ROT <=
AT-XY FORGET PAGE WORDS
Special My4TH Words
For a complete description of non-standard words, please read the
Forth Glossary for My4TH (pdf).
I2C-START I2C-RECV RINP RUN-IMAGE SX EDIT
I2C-STOP WOUT SAVE-IMAGE BLOAD SY RANDOM
I2C-SEND ROUT LOAD-IMAGE LCD TERMINAL SYSV
Forth Extension Modules
My4TH Forth implements the custom word BLOAD. With this word you can load binary
extension modules from the EEPROM into the RAM. Binary extension modules can,
for example, expand the Forth word set.
These Forth extensions are currently available:
String Words (m4-strings.bin)
BLANK CMOVE> /STRING -TRAILING SEARCH SLITERAL
Facility Extension Words (m4-facility.bin)
+FIELD EKEY>CHAR K-UP K-INSERT K-F3 K-F8
FIELD: EKEY>FKEY K-LEFT K-NEXT K-F4 BEGIN-STRUCTURE
CFIELD: EMIT? K-RIGHT K-PRIOR K-F5 END-STRUCTURE
EKEY K-DELETE K-END K-F1 K-F6
EKEY? K-DOWN K-HOME K-F2 K-F7
Floating-Point Words (m4-float.bin)
>FLOAT F0= FALIGN FFIELD: FNEGATE FTRUNC
D>F F< FALIGNED FLITERAL FOVER FVALUE
F. F>D FCONSTANT FLN FROT FVARIABLE
F! F>S FCOS FLOAT+ FROUND PRECISION
F* F@ FDEPTH FLOATS FS. REPRESENT
F+ FABS FDROP FLOG FSIN S>F
F- FACOS FDUP FLOOR FSQRT SET-PRECISION
F/ FASIN FE. FMAX FSWAP
F0< FATAN FEXP FMIN FTAN
Some notes about floating-point arithmetic on My4TH:
You must have at least the My4TH ROM v1.2 installed on your My4TH board, otherwise
you will not be able to enter floating-point numbers on the command line. This module implements
"FlexiFloat" by Jörg Völker, which is slightly less precise than IEEE-754
single precision floating-point numbers. Floating-point operations on My4TH are really slow,
and to speed up floating-point operations no rounding is implemented at all. Some mathematical
functions (especially exp, ln, log, asin, acos, atan) quickly become inaccurate when the numbers
get larger. The largest number that can be entered and printed is 8388607 (23 bit).
There is no separate floating-point number stack implemented, i.e. floats are stored on the data stack.
27.8e 1.12e f* f. 31.136 ok
1e+2 3e f/ fs. 3.33333E1 ok
1560.25e fsqrt f. 39.5 ok
1.0e fexp f. 2.71828 ok
If you haven't done it yet, please read the tutorial
"Starting Forth" by Leo Brodie
first. The tutorial contains many examples that you can try out on My4TH.
Another really good introduction to Forth is the Forth Primer
And so Forth...
by Hans Bezemer. This primer is also a collection of very useful Forth code snippets.
And this is another very good primer, especially for beginners:
A Beginner's Guide to Forth
Here are two examples of simple Forth programs that you can enter and run on My4TH:
The square root of an unsigned integer can be calculated this way:
: sqrt dup begin 2dup / over + 2/ swap over - abs 2 < until nip ;
The line above implements the Heron's method for finding the square root of a number.
The leading colon tells Forth to compile the new word "sqrt", which is built from all
the following words. The trailing semicolon tells Forth to exit compile mode again.
After you have entered the line, Forth will respond with "OK".
When you now enter
49 sqrt .
you will get the correct result 7.
Here is another example. The program below draws the Pascal's triangle:
: triangle cr dup 0 ?do 1 over 1- i - 2* spaces i 1+ 0
?do dup 4 .r j i - * i 1+ / loop cr drop loop drop ;
Note that the line is too long and does not fit into 80 characters. This is not a problem
because you can split the line in half. Forth does not leave compile mode until it sees the
terminating semicolon. Forth acknowledges the first line with "compiled"
and the second line with "OK".
To tell My4TH to print the first 10 lines of the triangle, you simply need to enter
and you will get this beautiful triangle:
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
1 6 15 20 15 6 1
1 7 21 35 35 21 7 1
1 8 28 56 70 56 28 8 1
1 9 36 84 126 126 84 36 9 1
Useful Forth links
Here are a few links to other Forth related sites that may be of interest to you:
My Forth implementation for My4TH deviates from the standard because I changed the memory layout
of the "words" a bit to increase the speed. The words are stored in a simple linked list in the
dictionary. The original implementation developed by Charles H. Moore is depicted below:
And this is the implementation on My4TH:
Each "word" is provided with a header containing the word name and a pointer to the next word
in memory. It is typical for Forth that the name is not represented as a null-terminated string, but as
length plus string. The string length is stored in a byte that precedes the string.
The field called "payload" contains the actual program code. This code can consist of machine code,
or a list of 16-bit address-pointers pointing to other words, which in turn are called like subroutines.
The implementation on My4TH now deviates in that a word in memory does not begin with its name but with the
pointer to the next word. This massively speeds up the search of the word list (the "dictionary"),
since no slow addition instruction is needed (otherwise, to get the pointer to the next word, one would have
to add the string length byte to the start address of the word to get a pointer to the pointer to the next word).
Also, My4TH does not use the classic "Direct Threaded Code" (DTC) model, which only contains
function pointers in the payload field. Instead, I chose the "Subroutine Threaded Code" (STC)
approach for My4TH for speed reasons. Here the code field of a word always contains only pure
machine code, and calling sub-words is actually done with a JSR call. This method unfortunately leads to
about 30% higher memory usage per word, since in addition to the 16-bit target address for a sub-word the
JSR instruction (8-bit) must also be stored. If you like to delve deeper into this topic, I recommend
Bradford J. Rodriguez, "Moving Forth".
To further increase the execution speed of Forth on My4TH, many Forth words are already stored in
highly optimized machine code in ROM. Thus, the Forth already has a decent size of 13 KB in ROM.
In contrast to the ROM, the RAM is still almost empty, so that the user still has 30 KB of free memory
available for self-defined words and programs composed of them. The layout of the RAM looks like this:
Traditionally, Forth works with two stacks: a data stack and a call stack. For reasons of speed the
two stacks share a common memory area on the My4TH computer, namely the processor stack. The call stack
occupies the upper half of the processor stack area from 8180h to 81FFh, and the data stack occupies
the lower half from 8100h to 817Fh. Both stacks are addressed with the usual fast stack instructions
PSH and POP.
Furthermore, two more stacks are implemented in My4TH Forth: The "Flow Control Stack",
which is needed by the compiler for the resolution of nested IF / ELSE / THEN's, and the
"Loop Control Stack", which is needed during runtime for loop variables (index and increment).
These two stacks could have been merged with the normal data stack, but separating the stacks has two
advantages: First, the limited storage space on the data stack is reserved for the actual data.
Second, the Loop Control Stack makes it easier for the Forth-newbie to program loops, since there
is no need to consider the loop parameters when accessing data on the stack. In fact, it can be quite
confusing if you cannot access data as usual on the data stack from within a loop that was placed
on the stack before you entered the loop. By the way, the flow control stack allows a nesting depth
of up to 32 IF / ELSE / THEN's, and the loop control stack allows up to 16 nested loops.
Ok, that's only half the truth. In my Forth implementation, there are actually two other stacks:
first, the extended return stack, which is accessed with the Forth words >r and r>, and the system
data stack, which is used for internal operating system functions. Separating these stacks from the
processor's return stack has two major advantages: Firstly, the available jump depth is increased by
freeing up the processor stack, and secondly, programming "screens" is much easier for
the beginner, who does not have to worry about screen block boundaries, since the Forth data and
return stacks still contain consistent data after the transition from one screen to the next,
and no control data is inserted by the system for housekeeping functions.
Useful things to know about Forth on My4TH
My4TH has a built-in editor that allows you to edit screens directly on the My4TH computer. To access
the editor, simply enter the number of the screen you wish to edit, followed by the word "EDIT".
Screen 0 is for documentation only
According to the Forth standard, screen number 0 cannot be used to store code. I recommend
to use screen 0 for documentation purposes only. For example, screen 0 can be used to maintain
a table of contents for the blocks currently in use.
Autostart mechanism after power on
You can configure a screen to be loaded automatically after My4TH is switched on. To do this, simply
write the screen number (decimal number) at the beginning of the first line in screen 0.
The RUN word
To standardize the way programs are started, I introduced the RUN word. You should add your own
RUN word to the end of your program, which acts as an entry point into your program
(like the "main" function in C). For example, once you have compiled your program
and stored it as a binary image in EEPROM, you can simply type "RUN-IMAGE" to load
and run your program with a single command.
Save binary program images
To speed up program loading, you can store precompiled binary images in EEPROM. When you have
completely entered your Forth program (or loaded and compiled all the screens you need),
you can use the word SAVE-IMAGE to store a binary RAM image in EEPROM. Binary screens can
then be loaded or loaded and run using the words LOAD-IMAGE and RUN-IMAGE.
My4TH Forth for the MyNOR computer
If you have already built a MyNOR computer and want to try My4TH Forth, you can download the
My4TH software package. The package contains the My4TH EPROM image files as well as an EPROM
image file specifically for MyNOR. For full compatibility with the my4th data transfer tool,
you should clock your MyNOR at 8 MHz, otherwise the serial baud rate will be too low.
My4TH Forth for MyNOR has limited functionality. It does not support the MyNOR expansion boards
(no LCD and keyboard support), and the available RAM is limited to 8 KB. To support all three
output ports of MyNOR, this special Forth variant implements the additional words
WOP1/WOP2/WOP3 and ROP1/ROP2/ROP3.
Data transfer between My4TH and a PC
I have written a tool called "my4th" which simplifies the data transfer between the
My4TH board and a PC. With this tool you can transfer the so called Forth "screens"
from a PC to the on-board EEPROM and vice versa. This makes developing your own Forth programs
much easier, since you can use your favorite text editor on the PC to edit the screens.
The my4th tool also has a special feature that allows you to load unformatted source code
("spaghetti code") into the EEPROM. However, my favorite method for testing
Forth code on the target platform is the "execute" mode of the my4th tool: In this special
mode, the tool sends your Forth source code line by line to the My4TH board for execution.
And as a bonus, if you are using Linux, the tool allows you to stay connected to My4TH via
its built-in terminal emulation mode. So you can upload your code to My4TH in the first step,
and then run and debug the code on the terminal console (without having to launch a separate
terminal emulator like putty). This is my favorite my4th command:
$ my4th exec /dev/ttyS0 file myforthprogram.txt -t
Another tip: The my4th tool uses the baud rate 4800 baud by default. If you clock your board
lower (e.g. with 4 MHz instead of 8 MHz), you can instruct my4th to connect with 2400 baud by
adding the -l option after the serial port name:
$ my4th exec /dev/ttyS0 -l file myforthprogram.txt -t
For a detailed description of the my4th transfer tool, please read this document:
You can find even more useful information
in the FAQ.