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.)

Core Words

  !              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

Block Words

  BLK            BUFFER         FLUSH          LOAD           SAVE-BUFFERS   THRU
  BLOCK          EMPTY-BUFFERS  LIST           REFILL         SCR            UPDATE

Double-Number Words

  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

Miscellaneous Words

  ?              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
 CMOVE          COMPARE

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.

Floating-point examples:

  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


Using Forth

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

10 triangle

and you will get this beautiful triangle:

                     1
                   1   1
                 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
 ok

Useful Forth links

Here are a few links to other Forth related sites that may be of interest to you:

  "Starting Forth" by Leo Brodie: https://www.forth.com/starting-forth
  "Thinking Forth" by Leo Brodie: https://thinking-forth.sourceforge.net/
  And so Forth... primer by Hans Bezemer: https://thebeez.home.xs4all.nl/ForthPrimer/Forth_primer.html
  Another very good primer for beginners: https://galileo.phys.virginia.edu/classes/551.jvn.fall01/primer.htm
  The computer language Forth (EN/NL/DE): https://home.hccnet.nl/anij/
  The website of the Forth 2012 Standard: https://forth-standard.org
  Forth on Restta Code: https://rosettacode.org/wiki/Forth
  Forth-Gesellschaft e.V. (only in German): https://forth-ev.de


Forth Implementation

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 reading 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

Built-in Editor

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: My4TH_Data_Exchange.pdf

Note:

You can find even more useful information in the FAQ.