\       Lesson 3 - How Forth Works

\       The Forth Course

\       by Richard E. Haskell

\          Dept. of Computer Science and Engineering

\          Oakland University, Rochester, MI 48309

 

comment: 

                                Lesson 3

 

                            HOW FORTH WORKS

 

                3.1  VARIABLES.........................................................................................   3-2

                3.2  MORE ABOUT VARIABLES -- FETCH AND STORE.........................    3-3

                3.3  CONSTANTS .......................................................................................    3-5

                3.4  THE FORTH COLON WORD :  ...........................................................    3-6

                3.5  ARRAYS ..............................................................................................    3-7

                3.6  THE RETURN STACK..........................................................................    3-8

                3.7  CODE WORDS......................................................................................    3-9

                3.8  THE FORTH DICTIONARY..................................................................    3-10

                3.9  TABLES.................................................................................................    3-11

                3.10  CHARACTER OR BYTE DATA..........................................................    3-12

                3.11  FINDING DICTIONARY ADDRESSES...............................................    3-13

                3.12  THE NAME FIELD...............................................................................    3-14

                3.13  OPERATION OF THE F-PC INNER INTERPRETER...........................    3-15

                3.14  EXERCISES ..........................................................................................   3-17

 

 

 

 


3.1  VARIABLES

The Forth word VARIABLE is a defining word used to define

     variable names.  If you type

       VARIABLE my.name

 

then Forth will create a new dictionary entry called my.name.  All dictionary entries have the same general form, consisting of a header (made up of a view field, a name field and a link field) and a body (made up of a code field and a parameter field).  In F-PC the header and the body are physically stored in separate segments.

(In the 8086/8088/80286 the 1 Mbyte address space is divided into 64 Kbyte segments.  A physical address is specified by a 16-bit segment address, seg, and a 16-bit offset address, off.  The total address is written as seg:off.  The segment address can begin on any 16-byte boundary, called a paragraph.  Therefore, to address any byte in memory, one has to specify both a segment address and an offset address.)

For the word MY.NAME the dictionary entry will look like this

 

                              HEADER                ________

                view field address --->  VFA | VIEW |

                                                              |---------|

                link field address  --->  LFA  |  LINK |

                                                             |----------|

                name field address ---> NFA |   7 M   |

                                                             |    Y .    |

                                                             |   N A   |

                                                             |   M E   |

                                                             |----------|

                pointer to CFA ------->          |  ^CFA | ---------|

                                                             |----------|            |

                                                  Head Segment YSEG   |

                                                                                      |

                                    BODY              ________         |

                code field address --->  CFA | CODE | <------|

                                                             |----------|

        parameter field address --->  PFA |    0 0    |

                                                             |----------|

                                                    Code Segment ?CS:

 

 

 

The view field contains a character count equal to the offset address of the beginning of the colon definition within the file.  It is used to locate the colon definition when you ask to VIEW the definition of a word.

The link field contains a pointer to the LFA of a previously defined word.

The name field contains the name, beginning with the character count and followed by 1-31 characters.

The pointer to CFA contains the offset address of the CFA in the code segment.  This segment address is given by the F-PC word

        ?CS:.

 

The code field contains code that will be executed when the name in the name field is interpreted.  This is called direct threaded code and is used by F-PC.  Many Forths use indirect threaded code in which the code field contains a pointer to the code that is executed.  For a VARIABLE the code field contains the three bytes corresponding to the instruction CALL >NEXT where >NEXT is the F-PC inner interpreter to be described later in this lesson.  The CALL instruction automatically puts the address of the next instruction on the stack.  In this case it is not the address of an instruction at all but rather the parameter field address.

The parameter field contains different things for different kinds of words.  For a VARIABLE word, the parameter field contains the 16-bit value of the variable.  An initial value of zero is stored in the parameter field when a VARIABLE is defined.

When you type the name of a VARIABLE the CALL >NEXT instruction in the code field will be exectuted which has the effect of leaving the parameter field address on the stack.  If you type my.name .

        the PFA of my.name will be printed.  Try it.

 

 


3.2  MORE ABOUT VARIABLES -- FETCH AND STORE

 

Forth words:

¡@

        !       ( n addr -- )   ( "store" )

                stores the value of n at addr

¡@

                6 my.name !

¡@

                will store the value 6 at the PFA of my.name.

¡@

        @       ( addr -- n )   ( "fetch" )

                reads the value at addr and puts it on the stack.

¡@

                my.name @ .

¡@

                will print the value of my.name.

¡@

Stack variables

 

The system variable SP0 contains the value of the stack pointer for an empty stack.  Thus,

             SP0 @

will return the address of the stack pointer when nothing is on the stack.

The Forth word SP@ returns the address of the last item pushed on the stack.  That is, it is the current value of the stack pointer.

The Forth word DEPTH returns the number of items on the stack.

It is defined as follows:

 

        : DEPTH         ( -- n )

                        SP@ SP0 @

                        SWAP - 2/ ;

¡@

Note that since each element on the stack is a word that contains  two bytes, the number of bytes on the stack must be divided by 2 to give the number of words on the stack.

 

 

 

 

 

 

 

 


3.3  CONSTANTS

The Forth word CONSTANT is a defining word that lets you define constants.  For example, if you type

                25 CONSTANT quarter

 the name quarter will be entered into the dictionary as follows:

                      ________

              VFA | VIEW |

                      |----------|

              LFA |  LINK |

                      |----------|

             NFA |    7 Q   |

                      |   U A   |

                      |    R T   |

                      |   E R    |

                      |----------|

                      |  ^CFA  | --------|

                      |----------|           |

           Head Segment YSEG   |

                                               |

                      ________         |

              CFA | CODE | <------|

                      |----------|

              PFA |     25    |

                      |----------|

            Code Segment ?CS:

 

The code field contains the three bytes corresponding to the instruction CALL DOCONSTANT.  The code at DOCONSTANT pops the PFA from the stack (where it was put by the CALL instruction) and then pushes on the stack the value stored at the PFA.  Thus,

        if you type

¡@

                25 CONSTANT quarter

¡@

        and then type

¡@

                quarter .

¡@

        the value 25 will be printed.

¡@

        NOTE:  The value stored in CONSTANTs are 16-bit signed numbers.

¡@

 

 

 

 

 


3.4  THE FORTH COLON WORD :

The Forth word : ("colon") is also a defining word that lets you define new Forth words.  When you type

                : squared  DUP * ;

 

the colon word : is executed.  It creates your Forth word squared as a dictionary entry that looks like this:

 

                      ________                                    ________

              VFA | VIEW |                   |----------->   |   DUP    | ES:0

                      |----------|                   |                  |------------|

              LFA |  LINK |                   |                   |      *      |

                      |----------|      ES = LSO + XSEG   |------------|

             NFA |    7 S    |                  |                   |UNNEST|

                      |   Q U   |                  |                   |------------|

                      |   A R   |                  |            List Segment XSEG

                      |   E D   |                  |

                      |----------|                 |

                      |  ^CFA | -------|       |

                      |----------|          |      |

        Head Segment YSEG    |      |

                                              |      |

                     ________         |      |

              CFA | CODE | <------|      |

                      |----------|                 |

              PFA |   LSO  | --------------|

                      |----------|

                  Code Segment ?CS:

 

 

The code field contains the three bytes corresponding to the instruction JMP NEST.  The code at NEST is part of the inner interpreter whose operation will be described later in this lesson.

The parameter field contains a list segment offset, LSO, whose value is added to the base list segment address contained in the variable XSEG.  The resulting segment address is stored in the register ES and the list of code field addresses making up the definition of squared is stored in memory starting at address ES:0.

UNNEST is the address of another routine that is part of the Forth inner interpreter.

 

 

 

 

 

 


3.5  ARRAYS

Suppose you want to create an array that contains five 16-bit values.

     If you type

                VARIABLE my.array

 

Forth will create the dictionary entry my.array that contains a single 16-bit value in its parameter field.

                      ________        |

              CFA | CODE | <------|

                      |----------|

              PFA |      00   |

                      |----------|

               Code Segment ?CS:

 

Here we have not bothered to show the head segment associated with the definition of my.array.  Note that the parameter field contains 2 bytes to store the 16-bit value.

The Forth word ALLOT will add n bytes to the dictionary in the code segment where n is the value on the stack when ALLOT is executed.

        Thus,

                8 ALLOT

¡@

will add 8 bytes, or 4 words to the dictionary.  The code segment part of the dictionary entry my.array will then look like this.

 

                      _______________        |

              CFA |        CODE        | <------|

                      |---------------------|

              PFA |    my.array(0)    |

                      |---------------------|

        PFA + 2 |     my.array(1)   |

                      |---------------------|

        PFA + 4 |     my.array(2)   |

                      |---------------------|

        PFA + 6 |    my.array(3)    |

                      |---------------------|

        PFA + 8 |     my.array(4)   |

                      |---------------------|

                     Code Segment ?CS:

¡@

 

To print the value of my.array(3) you could type

                my.array 3 2* + @ .

 

 

 

 


3.6  THE RETURN STACK

When you type a number it is put on the parameter stack.  All of the arithmetic operations and words such as DUP, ROT, DROP, SWAP, and OVER operate on numbers that are on the parameter stack.

Forth also has a second stack called the return stack.  The return stack is used by the Forth inner interpreter to store the return address of the next word in a colon definition.  It is also used by certain Forth words such as DO.

You can also use the return stack IF YOU ARE CAREFUL.  You can move a number from the parameter stack to the return stack temporarily if you are sure to move it back before the end of a colon definition.  Otherwise, the proper return address will not be on top of the return stack, and the inner interpreter will not be able to find its way back to the next word to execute.

The following Forth words use the return stack, R:

 

        >R      ( n -- )        ( "to-R" )

                pops the top element of the parameter stack

                and pushes it onto the return stack.

 

        Ex.  3 >R

                     moves 3 to the top of the return stack and

                     leaves the parameter stack empty.

 

        R>      ( -- n )        ( "from-R" )

                pops the top element of the return stack

                and pushes it onto the parameter stack.

 

        R@      ( -- n )        ( "R-fetch" )

                copies the top element of the return stack

                to the top of the parameter stack.

 

 

        Here is a possible definition of ROT:

 

        : ROT   ( n1 n2 n3 -- n2 n3 n1 )

                >R              \ n1 n2

                SWAP            \ n2 n1

                R>              \ n2 n1 n3

                SWAP ;          \ n2 n3 n1

 

 

 

 

 

 


3.7  CODE WORDS

Code words are Forth words that are defined in terms of 8086 machine code rather than in terms of other Forth words.  Of course, eventually some real 8086 machine code must be executed! The inner interpreter is written in machine code.  In addition, many of the F-PC Forth words are written in machine code to maximize their speed of operation.  In Lesson 7 we will show you how you can write your own Forth code words.

Since F-PC uses direct-threading, the machine code in a code word is stored directly at the CFA in the code segment.  Here are examples of how some F-PC primatives are defined.  In each case the header of the word is stored in the head segment in the same way as described previously for VARIABLES, CONSTANTS, and colon definitions.

                                                    DUP

                      _______________        |

              CFA |   MOV DI, SP   | <------|

                      |---------------------|

                      |     PUSH [DI]    |

                      |---------------------|

                      |   JMP >NEXT   |

                      |---------------------|

                     Code Segment ?CS:

 

 

                                                   SWAP

                      _______________        |

              CFA |     POP  DX       | <------|

                      |---------------------|

                      |       POP  AX     |

                      |---------------------|

                      |      PUSH DX    |

                      |---------------------|

                      |      PUSH AX    |

                      |---------------------|

                      |    JMP >NEXT  |

                      |---------------------|

                     Code Segment ?CS:

 

 

                                           @ ("Fetch")

                      _______________         |

              CFA |        POP  BX     | <------|

                      |----------------------|

                      |    PUSH [BX]     |

                      |----------------------|

                      |    JMP >NEXT    |

                      |----------------------|

                     Code Segment ?CS:

 

 

 

3.8  THE FORTH DICTIONARY

The Forth dictionary consists of a linked list of all words that have been defined.  These words can be variables, constants, colon definitions or code words.  The names of all of these words are stored in the head segment and linked by means of the link field pointers.  The code field of each word is pointed to by the code field pointer in the header.  The code field always contains real executable code and therefore must be in the 8086 code segment.  In a colon definition the list of CFA's for each word in the definition is stored in a separate list segment that is pointed to by a pointer at the PFA in the code segment.

When you define a new word using the colon definition, the compilation process consists of storing the word in the dictionary.  F-PC links the name of your word into one of 64 threads using a hashing scheme to increase the speed at which words can be found when searching the dictionary.

The next available address in the code segment of the dictionary is given by HERE.  That is, HERE is a Forth word that returns the next available address on the stack.  The variable DP, the dictionary pointer, contains this next available dictionary address.  The word

        HERE is just

                        : HERE  ( -- n )

                                DP @ ;

 

        (F-PC actually defines HERE as a CODE word.)

The outer interpreter is what is being executed when you boot up a Forth system and the ok prompt is displayed.  When you type a word and press <Enter> the outer interpreter searches the dictionary for the word you typed.  If it finds the word, it executes it by executing the code located at the code field address.  If it doesn't find the word, it executes a word called NUMBER that tries to convert your word to a valid number.  If it succeeds, it pushes the value of the number on the stack; otherwise, it displays the <- What? message that tells you that is doesn't understand your word. 

        We will take a closer look at the operation of the inner interpreter

        in Section 3.13.

 

 

 

 

 


3.9  TABLES

A table is like a constant array.  You could create an array and then fill the values of the array using the ! store word.

Another way to create a table is to use the Forth word CREATE which works the same way as VARIABLE except that no space is reserved in the parameter field.  For example, if you type

                CREATE table 

        you will create the following dictionary entry.

 

                                     table

                      ________         |

              CFA |  CODE | <------|

                      |-----------|

                            PFA          <---- HERE

 

                  Code Segment ?CS:

 

As with the case of a VARIABLE the code field contains the three bytes corresponding to the instruction CALL >NEXT where >NEXT is the F-PC inner interpreter.  The CALL instruction will leave the parameter field address on the stack when the word table is called.

At this point the dictionary pointer, DP, contains the value of the PFA of table.  The forth word comma (,) will store the value on the stack at the location pointed to by the dictionary pointer; that is, at the next available location in the dictionary.  Therefore, if you

        type

                CREATE table 5 , 8 , 23 ,

¡@

        the following dictionary entry will be created:

 

                                       table

                      ________         |

              CFA |  CODE | <------|

                      |-----------|

              PFA |       5     | 0

                      |-----------|

                      |       8     | 1

                      |-----------|

                      |      23    | 2

                      |-----------|

                  Code Segment ?CS:

 

        You could now define a new word called @table as follows:

 

                : @table        ( ix -- n )

                                2* table        \ 2*ix pfa

                                + @ ;           \ @(pfa + 2*ix)

¡@

        For example,  2 @table

        will return 23 to the top of the stack.

 

3.10    CHARACTER OR BYTE DATA

Character (ASCII) data can be stored in one byte.  Data can be stored and retieved from single bytes using the following Forth words:

        C,      ( c -- )        ("C-comma")

                Store least significant byte (LSB) of value on top of

                the stack at HERE (next available location in the

                dictionary).

¡@

        C!      ( c addr -- )   ("C-store")

                Store LSB of value on top of the stack at addr.

¡@

        C@      ( addr -- c )   ("C-fetch")

                Fetch the byte at addr.  Leave as LSB on stack.

 

 

You can create a table containing byte values rather than word values by typing

 

                CREATE table 5 C, 8 C, 23 C,

¡@

        You can then define a word called C@table as follows:

¡@

                : C@table       ( ix -- c )

                                table + C@ ;

¡@

        2 C@table will then return 23 to the top of the stack.

¡@

        Note the difference between C@table and @table defined in Section 3.9.

¡@

 

 

 


3.11  FINDING DICTIONARY ADDRESSES

The following words can be used to locate and examine Forth dictionary entries:

 

        '       ( -- cfa )      ("tick")

                The statement  ' table

                will leave the CFA of table on the stack.

¡@

        >NAME   ( cfa -- nfa )  ("to-name")

                Converts the code field address, CFA, (in the code segment)

                to the name field address, NFA, (in the head segment).

¡@

        >LINK   ( cfa -- lfa )  ("to-link")

                Converts the code field address, CFA, (in the code segment)

                to the link field address, LFA, (in the head segment).

¡@

        >BODY   ( cfa -- pfa )  ("to-body")

                Converts the code field address, CFA, (in the code segment)

                to the parameter field address, PFA, (in the code segment).

¡@

        You can go to the code field address by using

¡@

        BODY>   ( pfa -- cfa )  ("from-body")

        NAME>   ( nfa -- cfa )  ("from-name")

        LINK>   ( lfa -- cfa )  ("from-link")

¡@

        You can also go from NAME to LINK and from LINK to NAME using

¡@

        N>LINK  ( nfa -- lfa )  ("name-to-link")

        L>NAME  ( lfa -- nfa )  ("link-to-name")

 

The Forth word HEX will change the base used to print out values to hexadecimal.  The word DECIMAL will change the base back to decimal.  You can change to any base by storing the value of the base in the variable BASE.  For example, the definition of HEX is

                : HEX  16 BASE ! ;

 

Note that the base must be DECIMAL when this definition of HEX is loaded.

The Forth word U. prints the top value on the stack as an unsigned number between 0 and 65535, or if in the HEX mode, between 0000 and FFFF.  As an example, to print the hex address of the name field of the word OVER type

                HEX ' OVER >NAME U. DECIMAL

 

The Forth word LDUMP ( seg off #bytes -- ) can be used to get a hex dump of #bytes of memory starting at address seg:off.

        For example, type

                          YSEG @ ' OVER >NAME 20 LDUMP

¡@

        and see if you can see the name field of OVER.

 

3.12  THE NAME FIELD

When you define a new word such as TEST1 using a colon definition the following name field is created:

 

        Precedence bit ----|   |--- Smudge bit         Hex value

                           |   |

                    ___________________________________

           NFA  | 1 | 0 | 0 | Name char count = 5    |   85

                     |-----------------------------------------|

                     | 0 | Character #1  T = 54H (hex) |   54

                     |-----------------------------------------|

                     | 0 | Character #2  E = 45H           |   45

                     |-----------------------------------------|

                     | 0 | Character #3  S = 53H           |   53

                     |-----------------------------------------|

                     | 0 | Character #4  T = 54H          |   54

                     |-----------------------------------------|

                     | 1 | Character #5  1 = 31H           |   B1

                     |-----------------------------------------|

 

 

If the precedence