As one of many examples, suppose we are designing a washing machine. The high level definition might be:
: WASHER ( -- ) WASH SPIN RINSE SPIN ;
The colon indicates that a new word is being defined; following it is the name of the new word, WASHER. The remainder are the words that comprise this definition. Finally, the definition is terminated by a semi-colon.
Typically, we design the highest-level routines first. This approach leads to conceptually correct solutions with a minimum of effort. But in Forth — SwitfX's native "compiler compiler" language — words must be compiled before they can be referenced, so code listings begin with the most primitive definitions and end with the highest-level words.
A complete, annotated listing of the washing machine program is given below. Items in parentheses or following a backslash (\) are comments. The first few lines define a hardware port address (in this case, on a 68HC12) and six bit masks used to access individual bits on that port. Subsequent lines define application words that do the work.
The source code in this example is nearly self-documenting; the comments identify groups of words and show the parameters being passed to certain words. When reading,
: WASHER ( -- ) WASH SPIN RINSE SPIN ;
it is obvious what RINSE does. To determine how it does it, you read:
: RINSE ( -- ) FILL-TUB AGITATE DRAIN ;
When you wonder how FILL-TUB works, you find:
: FILL-TUB ( -- ) FAUCETS ON TILL-FULL FAUCETS OFF ;
Reading further, one finds that FAUCETS is a mask specifying the bit of the port that controls the faucet, while ON is a word that turns on that bit.
Even from this simple example, it may be clear that Forth is not so much a language as a tool for building application-oriented command sets. The definition of WASHER is based not on low-level Forth words, but on words with names like SPIN and RINSE that make sense in the context of the application.
When developing this embedded program, you would follow your top-down logic, as described above. But when the time comes to test the application code example using SwiftX's Cross-Target Link (XTL), you will see the real convenience of Forth's interactivity.
If your hardware is available, your first step would be to see if it works. Even without the code in the file, you could read and write to target hardware registers by typing phrases such as:
HEX PORT C@ .
The word C@ fetches a character (byte) from the address specified by PORT. This would read port address 01 and display its current bit values. The similar phrase PORT C! (used in ON and OFF) stores a value in the address.
You could also type:
2 ON 2 OFF
to see if the clutch, controlled by the bit masked by 2, engages and disengages. If the hardware is unavailable, you might temporarily re-define PORT as a variable you can read and write, and so test the rest of the logic.
You can load your source code file using the command INCLUDE <filename>, whereupon all functions defined in the specified file are parsed and available for testing. You can further exercise your I/O by typing high level, application-appropriate phrases such as:
…to see what happens. Then you can exercise your low-level words, such as:
…and so on, until your highest-level words are tested.
As you work, you can use any additional embedded systems programmer aids provided by SwiftX. You can easily change your embedding code and re-load it. But your main ally is the intrinsically interactive nature of Forth itself, the programming language with which SwiftX cross compilers are generated.
Parentheses and backslashes denote comments. Listings begin with primitive functions.
( Washing Machine Embedded Application ) \ Port assignments 01 CONSTANT PORT \ bit-mask name bit-mask name 1 CONSTANT MOTOR 8 CONSTANT FAUCETS 2 CONSTANT CLUTCH 16 CONSTANT DETERGENT 4 CONSTANT PUMP 32 CONSTANT LEVEL
A colon begins a new definition.
\ Device control : ON ( mask -- ) PORT C@ OR PORT C! ; : OFF ( mask -- ) INVERT PORT C@ AND PORT C! ;
Definitions can contain generic SwiftX words and any others you've defined…
\Timing functions : SECONDS ( n -- ) 0 ?DO 1000 MS LOOP ; : MINUTES ( n -- ) 60 * SECONDS ; : TILL-FULL ( -- ) \ Wait till level switch is on BEGIN PORT C@ LEVEL AND UNTIL ;
…so, application-specific functions are defined in terms of previous definitions…
\ Washing machine functions : ADD ( port -- ) DUP ON 10 SECONDS OFF ; : DRAIN ( -- ) PUMP ON 3 MINUTES ; : AGITATE ( -- ) MOTOR ON 10 MINUTES MOTOR OFF ; : SPIN ( -- ) CLUTCH ON MOTOR ON 5 MINUTES MOTOR OFF CLUTCH OFF PUMP OFF ; : FILL-TUB ( -- ) FAUCETS ON TILL-FULL FAUCETS OFF ; \ Wash cycles : WASH ( -- ) FILL-TUB DETERGENT ADD AGITATE DRAIN ; : RINSE ( -- ) FILL-TUB AGITATE DRAIN ;
…until you reach the main application definition.
\ Top-level control : WASHER ( -- ) WASH SPIN RINSE SPIN ;