Chapter 3. Forth/Open Firmware

Verbum sat sapienti

At the beginning of this book, I said I would talk about hardware, not software. There are many good books already written on C programming, embedded firmware development in C, porting Linux, coding in Python, writing Java software, and so on. However, there is one software topic that is rare, and chances are you may not happen upon it or become exposed to it. And that is a pity, because for the hardware developer, this topic can be very important. It is the programming language, Forth. So, I will break with the general “stuff you can kick” theme of this book to give you an overview of this important language.

Introducing Forth

Forth was originally written by Charles (Chuck) Moore (http://www.colorforth.com/bio.html) in 1970 to control the 30 ft telescope at the Kitt Peak Observatory. When he created Forth, Charles Moore envisioned that the “fourth” generation of computers would be distributed controllers, in essence embedded systems, although that term had not yet been invented. Hence, he called his programming language “Fourth.” However, since the machine that was used for development allowed only five-character filenames, the programming language became simply Forth. The name has stuck ever since.

Forth is unlike any other conventional programming language (although there are some vague similarities to Adobe’s PostScript). Forth is an extensible, highly interactive, stack-based language. It is extremely efficient and extremely versatile. In addition, Forth is relatively easy to “bring up” on a virgin machine, and the structure and functionality of the language make it ideal for debugging both system hardware and software. In fact, it is fantastic for debugging new hardware. Forth is commonly used in systems under development and is often retained by manufacturers in their computers. You can often find Forth sitting deep inside a machine’s ROM. NASA’s Voyager spacecraft run Forth, providing for both efficient firmware and the ability to interactively debug across the vastness of space, and Forth is also used by NASA in the Space Shuttle’s Star Tracker subsystem. (More information may be found at http://forth.gsfc.nasa.gov.) The Open Firmware standard (IEEE 1275) is based on Forth and is used by both Apple Computer and Sun Microsystems, as well as many others. Hardware engineers love Forth. Traditional computer scientists hate it.

Tip

If you have an Apple Macintosh and like living life on the edge, hold down command-option-O-F immediately after pushing the power button. You’ll boot into the Open Firmware Forth instead of Mac OS X.

Forth is predominantly written in Forth and is interpreted by itself at runtime. The virtual machine running Forth is typically coded directly in the assembler both for speed of operation and to take advantage of the characteristics of the target computer directly. Moore explains that his concept for Forth is that each implementation of the language should be optimized to take advantage of the machine it is running on, even if this optimization compromises the portability of the language. This philosophy is a major departure from conventional programming ideology. With Forth, speed and robustness are the goals, not the ability to port applications between platforms.

Forth is at once a compiler, an interpreter, and, in a fashion, an operating system too. The majority of computer languages share many characteristics, many of them coming from common origins. Languages in this category include C and C++, Pascal, Modula-2, ADA, Fortran, and BASIC, to name just a few. With the exception of BASIC, which is (typically) an interpreted language, all these languages are compiled. Forth is also a compiled language, but it is a compiled language with a difference. It is interactive. Commands (known as words in Forth) get an immediate response. This, coupled with Forth’s ability to talk directly to hardware, makes it an excellent environment for hardware development.

Forth allows the execution of any subroutine (word) of a program in isolation. The programmer is also able to create new programs (words) based on previously defined words. So rather than writing a single, large program, small segments of code are written and tested independently. These words are then combined to create new words, eventually ending up with a single word that is the whole program. This new word is also available to the programmer, and in this way the language both grows and becomes richer as the programmer works with it. In addition, the words used to create the new word are still available and can be run as programs in their own right or used to create other new words. This modular form of program construction makes Forth a “bottom-up” language, rather than the conventional “top-down” programming methodology. This interactive, yet low-level, nature makes Forth a very powerful tool for debugging microprocessor hardware. Words written to interact with specific aspects of hardware (at the initial debugging stage) may be later incorporated in higher-level diagnostics or in the final application itself.

The most notable aspect of Forth is that data (arguments) are passed to the words (subroutines, if you like) via a stack. (Note that this stack is not necessarily the processor’s stack. Often it is a virtual stack created by the Forth kernel.) While it is true that many languages use stacks for parameter passing, the programmer is usually unaware of this aspect. Forth, however, is quite different. In Forth, arguments required by a word are pushed onto the stack explicitly, and then the word is called. The values can be pushed or pulled from the stack by other words or by the user.

In Forth, the words that a programmer writes directly manipulate the stack, taking parameters off and putting new values (return parameters) back. In addition, the programmer can directly manipulate the stack at the prompt, manually pushing or popping stack values prior to running a given word. This feature encompasses the power and beauty of Forth. As a consequence of the stack, Forth uses a form of syntax known as Reverse Polish Notation (RPN). Anyone who has used an old-style Hewlett-Packard calculator is familiar with RPN. In this notation, the operator follows the arguments. So the conventional expression a + b becomes a b + in RPN. In this example, first the number represented by a is pushed onto the stack, then b. In Forth, the + word takes these values off the stack, performs the addition, and places the result back on the stack.

So:

4  5  +

gives a result of 9 on the top of the stack. To display this result, we use dot (.), which pulls the topmost value from the stack and prints it to the console as a signed number. As an example, to add three numbers together and print the result, we would type the following at the prompt:

5  25  98  +  +  .

The first + adds 98 and 25, leaving the result on the stack. The second + adds this result to 5. This could also be done as:

5  25  +  98  +  .

Most versions of Forth use signed 16-bit numbers, although there are some Forths that are explicitly 32-bit. 16-bit Forths do provide access to 32-bit arithmetic using doubles.

By default, Forth works in base 10 (decimal). hex changes the base to base 16, and decimal returns it to base 10. As an example, let’s add (hex) 0x4F to (decimal) 255 and print out the result in decimal:

hex 4f decimal 255 + .

This gives a result of 334 on the console.

To output the top stack value as an unsigned number, use u. rather than the . operator. To output a right-justified number, use the .r word, which uses the top parameter to specify the spacing for the second parameter. For example:

123456  6  .r
1234  6  .r
12  6  .r

results in the following output:

123456
  1234
    12

Standard arithmetic is available using +, -, *, and /. These arithmetic operators are Forth words, and so must be surrounded by spaces. To multiply 2 and 3:

2  3  *

The / operator performs integer division. In some Forths, this rounds toward zero. In other Forths, it rounds toward minus infinity. To divide 9 by 3:

9  3  /

We can increment the top of the stack using the word 1+ and decrement it using 1-. As a nonsensical example, to convert 2 to 3:

2  1+

Let’s take a look at some words common to all/most implementations of Forth. I won’t provide an exhaustive list, as a complete discussion of the language would take a book in its own right. Remember, all words in Forth must be separated by one or more spaces.

String Words

We’ll start with that perennial favorite of programmers, “hello world,” to illustrate how to print out a string of characters. The word to output a string is ." (pronounced dot quote) and is used thus:

." hello world"

Note the space between ." and the string, and the absence of a space before the final quote. That’s because ." is a Forth word, and all words must be separated by a space. The final quote character is not a Forth word, merely a string terminator.

A carriage-return/line-feed pair is output using the Forth word cr , and a space is output using space. For more than one space, use the spaces word that takes a parameter from the stack to specify the number of spaces to be printed. For example, the following code prints 20 spaces to the console:

20 spaces

To output a number as an ASCII character, we use the word emit . This is equivalent to the C function putchar. For example, to output an asterisk, we would use:

42 emit

The Forth word key waits for a character to be input from the console, and the word key? (key query) checks to see if a key has been pressed. Note that I have seen some implementations of Forth that use different words for character input. As the saying goes, your mileage may vary.

The word expect is used to input a string of characters from the console.

Warning

Some Forths don’t use the word expect, but use the word accept instead. accept works in exactly the same way as expect.

expect uses two parameters from the stack. The topmost parameter (the last parameter to go on the stack) is the number of characters to be read from the console. expect will wait for this number of characters to be entered or for a carriage return to be typed, whichever comes first. The other parameter used by expect is a pointer (address) to a scratchpad in memory where the string is to be placed. How do you know where to put a string? Easy, Forth has a scratchpad already for you. Use the word pad to place the address of the scratchpad onto the stack.

Tip

Note that the scratchpad is not fixed in memory. It is merely a temporary storage place for strings. As words are defined and memory is used, the address supplied by pad will change.

To show you how this works, here is some code that will input 20 characters from the console:

pad 20 expect

Stack Manipulation

Since all words operate using parameters on the stack, Forth provides tools for the programmer to change the contents of the stack, or to alter the order of values on the stack.

The Forth word .s shows the current stack without removing any entries. This is a useful tool for the programmer, enabling you to nondestructively monitor the stack.

Other useful stack words are dup (duplicate the entry on top of the stack), drop (discard the entry on top of the stack), swap (exchange the two top entries on the stack), and over (copy the second-to-the-top entry to the top of the stack).

For example, entering 5 dup results in 5 5 on the stack. 3 4 swap results in 4 3 on the stack. 1 2 over results in 1 2 1 on the stack. dup is most often used to preserve stack entries when they are used with words that remove values from the stack. For example, here is Forth code that prints out the ASCII character A with its corresponding numeric code:

65 dup emit space . cr

Since both emit and . take a parameter from the stack, a dup is required to produce two copies of the required operand.

?dup will duplicate the top of the stack only if it isn’t zero. 2dup will duplicate the top two stack entries. For example:

10 23 2dup

gives:

10 23 10 23

Similarly 2swap, 2over, and 2drop also operate on the top two stack entries.

The Forth word rot rotates the third stack parameter to the top. For example:

1 2 3 rot

results in:

2 3 1

The word -rot rotates the other way and is, in effect, the exact opposite of rot:

1 2 3 -rot

This gives:

3 1 2

The word pick allows you to arbitrarily grab an item from the stack, with the top-most stack entry specifying from where the item comes. For example, n pick will pick the n th item from the stack.

Warning

pick will work in different ways depending on which variety of Forth you are using. Consult the documentation specific to your Forth.

Forth-79 and FIG Forth have pick numbering that starts from 1. So if our stack looks like:

54 46 32 29 10 5

then:

3 pick .

will output 29 to the console.

However, Forth-83, ANSI Forth, and gnu Forth have pick numbering that starts from 0. If you are using one of these Forths (with the same stack values), then:

3 pick .

will output 32 to the console.

The word nip removes the second item from the stack, while the word tuck copies the top item to the third position:

78 12 nip

This gives:

12

and:

78 12 tuck

gives:

12 78 12

Creating New Words

A new word is created by using a colon definition . An example of this is shown in Figure 3-1. This simple program prints “A” to the console.

Colon definition
Figure 3-1. Colon definition

The colon (:) tells the compiler that a definition is starting, and that what comes next is the name of the word, in this case “fred.” The definition is finished with a semicolon ( ;), the equivalent of a return in C or assembler. Everything in between : and ; constitutes the new program. In this example, the decimal value of 65 (the ASCII code for “A”) is loaded onto the stack, and then the word emit is called. To run our new word, we simply type fred at the prompt. To run fred three times, we simply type fred fred fred at the prompt.

Forth uses threaded code , which is a list of subroutine identifiers (words). Each word within a program is called in turn, thus producing the sequence of running code. The interpreter is responsible for calling words as appropriate and is capable of only three operations. The first of these is the call , which, as the name implies, begins execution of a given word. The second operation is known as the next operation and passes control from one word to the next word in the list. The return operation passes control back to the calling list of words. The call is often known as nesting , and the return is known as unnesting . As a consequence of this structure, Forth is capable of recursion; the degree of recursion (or nesting) is limited only by the available memory.

Forth uses two stacks for its operation. The first stack is the parameter stack used to pass data between words. The second stack is the return stack and holds the return addresses for currently running words. Typically, the return stack is the system stack of the processor. Often, both stacks are implemented within a virtual machine (in the same way that Java runs under a virtual machine). The virtual machine also has an Interpretive Pointer (IP), the equivalent to the instruction pointer (or program counter) of a conventional processor. A Word Pointer (WP) is used to track words within a definition.

Words are stored in a linked list known as a dictionary , shown in Figure 3-2.

Dictionary structure
Figure 3-2. Dictionary structure

In this data structure, words are stored in their order of definition. So when the user types fred on the console or uses fred in a word definition, Forth looks through the dictionary for a match and then simply calls the appropriate subroutine.

Writing your own Forth for your target machine is easy. It is simply a set of stack- manipulation primitives, a string parser, and a simple compiler. The compiler is trivial as it just builds a list of subroutine addresses, adds a return instruction, and then adds an entry in the linked list.

Words may be redefined by the programmer, the new word appearing in the dictionary list before the previous definition. When the input is parsed by the Forth interpreter, the dictionary is searched for a match. Thus, a redefined word will be matched before the parser reaches an earlier definition. Early words that used the prior definition reference that word by its address rather than its dictionary entry, and therefore still point to the original definition. Thus, redefining a word will not compromise the operation of other words based on the earlier definition. However, if a word is redefined as a bug fix, other words relying on it must subsequently be re-compiled to use the newer definition.

It is possible to redefine a word based on a variation of its previous definition. For example, a word fred may be redefined to run its previous definition twice:

:  fred
      fred fred
;

In this example, the new dictionary entry fred points to code that executes the previous definition of fred twice, referenced by the address of the original fred. When the compiler creates a new entry for fred, it searches the dictionary for the old reference, adding a subroutine call to the appropriate address. The original code for fred still exists in memory and is accessed by the call to its address. When you type fred at the prompt to run the new word, Forth searches the dictionary until it finds a match. Forth finds the newer definition first, and that is the code that is executed. Words that were written to use the previous definition of fred still work, as they reference that word by its address in memory.

Now, since Forth is written in Forth with much of the compiler and language sitting in the dictionary as Forth words, it is possible (and completely legal) to redefine the compiler (or aspects of the compiler) while it is running! Try doing that in C!

Comments

Comments in Forth are enclosed in parentheses:

(Here is a comment)

Note the spaces before and after the parentheses. The parentheses are Forth words, and therefore the spaces are required. Leaving the spaces out will not work:

(This ISN'T a comment)

Forth will try to interpret (This, ISN'T, a, and comment) as individual words, and if it does not find them in the dictionary (word list), it will complain bitterly.

Comments are also used to specify stack diagrams. A stack diagram indicates the stack usage of a word, as well as what it does. The general format of a stack diagram specifies the parameters taken off the stack (N1), the parameters placed back on the stack (N2), and a comment indicating the purpose of the word:

wordname (N1 -- N2 , what this word does)

Here are stack diagrams for some common Forth words:

1+ (N -- N+1, increments the top of the stack)
dup (N -- N N, duplicates the top of the stack)
swap (A B -- B A, swap top two values on stack)

Typically, stack diagrams are used within a word definition as a simple way of documenting the stack use and purpose of a word. Here are some examples:

: helloworld (-- , says hi)
    ." hello world"
;
 
: square (A -- A*A , squares top of stack)
    dup *
;

Because stack diagrams are comments, exactly how you specify the parameters is up to you, just so long as it makes sense to you and to anyone else likely to read your code.

if ... else

Forth has if ... else ... like other languages, but the structure is quite different from that which you are used to. if treats the topmost stack entry as a boolean. Any nonzero value is considered as true. Here is some sample code that shows you how to use if:

: is_it_true
   if
     ." That is true"
     cr
   else
     ." Not true"
     cr
   then
;

Note that the if statement is terminated by then. This is somewhat counterintuitive if you’re used to other programming languages. To show how this new word works, if we typed:

5 is_it_true

we’d get:

That is true

but, if we typed:

0 is_it_true

we’d then get:

Not true

For a simple if statement with no need of else, the format is simply:

: is_it_true
   if
     ." That is true"
     cr
   then
;

Now, rather than using then to end the if structure, you can also use endif:

: is_it_true
   if
     ." That is true"
     cr
   endif
;

then and endif work in exactly the same way. Using endif rather than then makes code a little easier to read. Which code structure you use is up to you.

Loops

Loops may be created using the Forth words do and loop. The following simple example prints out five new lines:

5  0  do
  cr
loop

This is equivalent to the following for loop in C:

for (i = 0; i < 5; i++)
{
   printf("
");
}

Tip

Note that in some Forths, the loop constructs described in this section may be used only inside word definitions. Gnu’s gforth is an example of such a Forth. In other Forths, you can quite happily use them from the command line. It all depends on which implementation you are using.

Now in C, you’re not limited to incrementing the loop counter by 1. Forth doesn’t have this limitation either. Instead of using loop, the word +loop takes a value from the stack and uses it to increment the loop count. Here is an example where the loop is incremented by 2 each iteration:

10 0 do
   cr
2 +loop

This is very versatile. In the previous example, the value by which the loop was incremented was specified just prior to +loop. However, since +loop takes a value from the stack, that value could just as easily be unspecified until runtime, and it could also be varied for each iteration of the loop simply by modifying that stack entry.

do (destructively) takes two operands off the stack and uses these for the loop count. In the previous examples, the loop executes the word cr five times. The operands can just as easily be supplied by other Forth words. In this example, the loop executes twice:

100 98 - 0 do cr loop

Alternatively, a word definition using do ... loop may take one or both of the loop operands from the stack. In the following example, the number of times to execute the loop is left to the user at runtime:

: stars (N -- , prints N asterisks to the console)
    0 do
    42 emit
    loop
;

To output 10 asterisks:

10 stars

The loop count is accessible inside the loop using the Forth word i. In this example, we print out the loop count as the loop executes:

10 0 do i . cr loop

Loops can also be nested. In this example, 50 spaces are printed to the console:

10 0 do 5 0 do space loop loop

A counter for the outer loop can be accessed by the Forth word j:

10 0 do 5 0 do i . space j . loop cr loop

This is not limited to two nested loops:

10 0 do              (loop 1)
   5 0 do            (loop 2)
      i j            (counts of loops 2 and 1)
      20 0 do        (loop 3)
        i           (count of loop 3)
        4 0 do      (loop 4)
            10 0 do  (loop 5)
               i j   (counts of loops 5 and 4)
            loop
         loop
      loop
   loop
loop

As you can see, at any stage, i can be used to access the count of the current loop, and j can be used to access the count of the loop containing the current loop. For three nested loops, access to the outermost counter is provided by k.

The mechanics of do ... loop are interesting. do places the top two stack parameters onto the return stack and sets up a target address to which loop branches back. This target address is that of the word immediately following do. When loop executes, it increments a counter and compares this with the loop limit on the return stack. If they are equal, the loop terminates; otherwise, execution branches back to the target address set up by do.

A loop can be prematurely terminated by using the leave word. For example, this loop will execute 10 times, provided a key is not typed:

10 0 do
   key? if leave endif
loop

key? checks whether a character has been input from the console and places a boolean onto the stack to indicate this. if removes the boolean and conditionally executes the leave word.

Conditional loops are created using the Forth words begin and until. until checks for a boolean on top of the stack. If one is found, the loop terminates; otherwise, execution branches back to the word following begin. The following example word reads characters from the console until an “A” is typed:

: wait_for_A
      begin
         key
         65 =
      until
;

The equal operator (=) takes the top two values from the stack (in this case, the ASCII code obtained using key and the value 65) and compares them. If they are equal, it places a true (-1) on the stack; otherwise a false (0) is placed on the stack. The Forth operator = is equivalent to == in C.

An alternative conditional loop construct is begin condition while code repeat. Everything between begin and repeat is executed with each iteration, but only provided that the condition is met. The code between begin and while is used to evaluate the condition, thus determining whether execution will continue or whether the loop will terminate. For example, the following word definition will run only while the user types an “A” on the console:

: while_A
      begin
         key 65 =
      while
         ." That was an A"
         cr
      repeat
;

Infinite loops may be implemented using begin ... again. Here is a word that, once run, will never terminate:

: semper
      begin
         ." Once more through the loop, dear friends."
         cr
      again
;

Such loops are particularly useful in embedded systems, where the code must repeat forever.

Warning

The Forth-83 standard doesn’t implement begin ... again. Instead, use begin 1 while ... repeat or begin ... 0 until as a replacement.

Forth-79, ANSI-Forth, and gnu Forth do implement begin ... again, so if you’re using one of those Forths, you have nothing to worry about.

Data Structures

The fact that Forth uses a stack for parameter passing between words makes it very powerful. It is because of the stack that the language is re-entrant and supports recursion. However, the dynamic nature of the stack makes it unsuitable for global data. Fortunately, Forth is not limited to using the stack, as the language provides for both named constants and variables.

A constant is declared by placing the value for the constant onto the stack, then the word constant followed by the constant name. For example, the following code declares a constant called kilobyte (representing the number of bytes in a K) to have a value of 1024:

1024 constant kilobyte

Using the constant in your code is trivial. Simply use the constant name to place the value onto the stack:

kilobyte

For example, here is a word definition that takes a value from the stack for a number of kilobytes, converts this into bytes, and prints out the result:

: kilobytes  (N --  , convert N to bytes)
   kilobyte  *  .
   ." bytes"  cr
;

So, typing:

32 kilobytes

gives a result on the console of:

32768 bytes

There is an alternative way to declare a constant. Simply define a word that places that value onto the stack:

: myconstant
    908612
;

This is not as efficient as using the constant word, but it works just the same.

Variables are declared in a similar way to constants, but the way they are used is quite different. Rather than placing a value onto the stack, the variable name will place a pointer to the variable onto the stack. A variable is declared by placing an initial value for the variable onto the stack, then the word variable followed by the variable name:

0 variable my_var

The pointer is used in conjunction with the words @ (pronounced fetch ) and ! (pronounced store ). Let’s say we want to make my_var equal to 32. We do it by placing the value (32) onto the stack, using the variable name to place the pointer onto the stack, and then using store to assign the value to the variable:

32 my_var !

To recall the variable’s value, we use the variable name to place the pointer onto the stack and then use fetch to retrieve the value and place it on the stack:

my_var @

For example, let’s say we want to add 5 to the current value of my_var:

my_var @   (get the current value)
5 +        (add 5)
my_var !   (put the result back into my_var)

This might seem a bit strange, but it is very close to what goes on behind the scenes when you say my_var = my_var + 5; in C. In C, the mechanics of the process are hidden from you. In Forth, the nuts and bolts are there for all to see (and to play with).

Interacting with Hardware and Memory

Forth is great for debugging embedded hardware. You can use Forth to examine the contents of memory or peripheral registers:

2000 @

This places the content of address 2000 onto the stack. You can also use Forth to set memory or peripheral registers:

41 2000 !

This sets the content of address 2000 to 41. Remember that you can do this from within a word or interactively from the command prompt. This means that from the prompt, you can interactively probe and change peripheral registers—a very powerful debugging tool.

Warning

If you’re using a version of Forth that is running on a desktop computer (such as a Mac or PC), don’t try using store (!) or any other word that directly modifies memory, as it may have unforeseen (and possibly disastrous) results.

Fetch (@) and store (!) work with 16-bit-wide locations. To access 8-bit-wide locations, use the words c@ (“c-fetch”) and c! (“c-store”), respectively. To access 32-bit-wide locations, use 2@ and 2!.

Warning

On some versions of Forth, such as gnu’s gforth running on a PowerPC processor, @ and ! operate on 32-bit values rather than 16-bit values. Similarly, on the same platform, 2@ and 2! are 64-bit operations.

As an example, let’s create a Forth program called status that will read the content of an 8-bit register located at address 2100 and place the result onto the stack.

: status 2100 c@ ;

This can be manually run from the prompt to examine the register during debugging:

status .

Perhaps you would like to continually monitor the status register while you tweak some hardware. Here is a Forth program that will do just that, until you press a key on the console:

: showstatus
   begin
      status .
      cr
      key?
   until
;

Once debugging is complete, the word status can be used as part of the main application:

: main
   begin
      status 5 =
   until
   41 TxRegister c!
;

The word dump is useful for examining a region of memory. dump takes two operands from the stack in the form address size dump. For example, to output 256 values starting at the current scratchpad location:

pad 256 dump
   BB1D4: 0C 30 C3 0C  C3 0C 30 C3 - 0C 30 C3 0C  33 33 33 30  .0....0..0..3330
   BB1E4: C3 0C 30 C3  0C 30 C3 0C - 30 C3 0C 30  C3 0C 30 30  ..0..0..0..0..00
   BB1F4: C0 C0 C0 C3  0C 2C 2F 89 - 09 24 24 90  92 49 09 02  .....,/..$$..I..
   BB204: 42 00 00 00  20 B0 B0 B0 - 90 90 B0 00  3C 00 00 00  B... .......<...
   BB214: 00 00 00 00  00 00 00 00 - 00 00 00 00  00 00 00 00  ................
   BB224: 00 00 00 00  00 00 00 00 - 00 00 22 42  42 42 49 32  .........."BBBI2
   BB234: 4C 92 4C 24  09 02 42 42 - 40 92 49 09  09 24 24 90  [email protected]..$$.
   BB244: 24 09 02 42  4B C0 BF CB - C9 30 AD C3  0B 30 2F F0  $..BK....0...0/.
   BB254: 0B B8 BF 82  FE 2B 8B E2 - FC BF 2F E2  FF FE 2F FC  .....+..../.../.
   BB264: 2F 8B FF BF  2F FE FC 2B - 7F BB DD FF  7F F8 2F 7D  /.../..+....../}
   BB274: F8 AF FF BF  E2 F0 B7 FC - AC 2A D8 AB  FF F7 F0 AD  .........*......
   BB284: E2 FE DF 0A  F0 B7 DE FB - C2 DF E0 AF  2F FE 2F CB  ...........././.
   BB294: E2 AE 2A E0  90 90 BF 0B - F0 BE 2F 8B  2C B2 CB F8  ..*......./.,...
   BB2A4: BE 24 92 49  24 92 4B FF - 2F 8B F0 80  00 02 DB F7  .$.I$.K./.......
   BB2B4: FE 08 00 00  2D BF 7F E2 - FF 2B FF BF  2F FE 2F FE  ....-....+.././.
   BB2C4: 2F FF F8 BF  DF FF 8B DE - 2B EF B7 CB  FE 2F FF FF  /.......+..../..

For each line, dump prints out an address followed by 16 bytes of data and the ASCII interpretation of those bytes. Any hex byte that doesn’t have an ASCII representation appears as a dot.

Memory can be cleared (each location made equal to 0) using the erase word. For example, to write 32 zeros starting from address 2100:

2100 32 erase

Similar to erase, fill can be used to fill a region of memory with a particular value. In this example, we store the value 255 to 32 locations starting from 2100:

2100 32 255 fill

Forth Programming Guidelines

As with any other programming language, it’s possible to write good Forth, and just as easy to write bad Forth. Here are some Forth tips:

  • Limit your stack usage to three or four words. Any more than this, and you will find it very hard to keep mental track of where you’re up to.

  • Use several short word definitions rather than one long word definition. Don’t ever create a Forth word that is hundreds of lines of code long. The beauty of Forth is its ability to build upon itself, allowing you to test as you go. To this end, keep your Forth words to three or four lines of code where possible. That might sound strange if you’re used to other languages, but once you get into the swing of Forth, you’ll understand that this is a logical approach to coding.

  • Keep it simple and focus on what you’re trying to achieve. A simple Forth word that solves a specific, simple problem is better than a complicated do-all word that is difficult to write and hard to debug.

  • Check for data that is out of range or erroneous and generate useful error messages or diagnostics.

There’s a lot more to this powerful language than I’ve shown here. For more information on Forth, visit the Forth Interest Group (FIG) at http://www.forth.org or go to Forth, Inc. at http://www.forth.com. Charles Moore, the creator of Forth, has a web site at http://www.colorforth.com. If you’d like to play with Forth, there are dozens of free Forths available for download over the Internet. For gnu’s Forth, go to http://www.gnu.org/software/gforth. Alternatively, just use your favorite search engine to search for a Forth for your platform.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.141.40.134