This chapter introduces Forth as it is implemented in OpenBoot. Even if you are familiar with the Forth programming language, work through the examples shown in this chapter; they provide specific, OpenBoot-related information.
The version of Forth contained in OpenBoot is based on ANS Forth.
Appendix E
lists the complete set of available commands. Words that are specifically used for writing OpenBoot FCode programs for SBus devices are described in the manual,
Writing FCode 2.x Programs
.
|
Note - This chapter assumes that you know how to enter and leave the User Interface. At the ok prompt, if you type commands that hang the system and you cannot recover using a key sequence, you may need to perform a power cycle to return the system to normal operation.
|
Forth Commands
Forth has a very simple command structure. Forth commands, also called Forth words, consist of any combination of characters that can be printed--for example, letters, digits, or punctuation marks. Examples of legitimate words are shown below:
@
dump
.
0<
+
probe-pci
To be recognized as commands
, Forth words must be separated by one or more spaces
(blanks). Pressing Return at the end of any command line executes the typed commands. (In all the examples shown, a Return at the end of the line is assumed.)
A command line can have more than one word. Multiple words on a line are executed one at a time, from left to right, in the order in which they were typed. For example:
is equivalent to:
ok testa
ok testb
ok testc
ok
|
In OpenBoot, uppercase and lowercase letters are equivalent. Therefore,
testa
,
TESTA
, and
TesTa
all invoke the same command. However, words are conventionally written in lowercase.
Some commands generate large amounts of output (for example,
dump
or
words
). You can interrupt such a command by pressing any key except
q
. (If you press
q
, the output is aborted, not suspended.) Once a command is interrupted, output is suspended and the following message appears:
Press the space bar (
<space>
) to continue, press Return (
<cr>
) to output one more line and pause again, or type
q
to abort the command. When you are generating more than one page of output, the system automatically displays this prompt at the end of each page.
Using Numbers
Enter a number by typing its value, for example, 55 or -123. Forth accepts only integers (whole numbers); fractional values (for example, 2/3) are not allowed. A period at the end of a number signifies a double number. Periods or commas embedded in a number are ignored, so 5.77 is understood as 577. By convention, such punctuation usually appears every four digits. Use one or more spaces to separate a number from a word or from another number.
OpenBoot performs 32-bit integer arithmetic, and all numbers are 32-bit values unless otherwise specified.
Although OpenBoot implementations are encouraged to provide a hexadecimal conversion radix, they are not required to do so. So, you must establish such a radix if your code depends on a given base for proper operation.
You can change the operating number base with the commands
octal
,
decimal
and
hex
which cause all subsequent numeric input and output to be performed in base 8, 10 or 16, respectively.
For example, to operate in decimal, type:
To change to hexadecimal type:
Two simple techniques for identifying the active number base are:
ok 10 .d
16
ok 10 1- .
f
ok
|
The
16
and the
f
on the display show that you are operating in hexadecimal. If
10
and
9
showed on the display, it would mean that you are in decimal base.
8
and
7
would indicate octal.
The Stack
The Forth
stack is a last-in, first-out buffer used for temporarily holding numeric information. Think of it as a stack of books: the last one you put on the top of the stack is the first one you take off.
Understanding the stack is essential to using Forth
.
To place a number on the stack, simply type its value.
ok 44 (The value 44 is now on top of the stack)
ok 7 (The value 7 is now on top, with 44 just underneath)
ok
|
Displaying Stack Contents
The contents of the stack are normally invisible. However, properly visualizing the current stack contents is important for achieving the desired result. To show the stack contents with every
ok
prompt, type:
ok showstack
44 7 ok 8
47 7 8 ok showstack
ok
|
The topmost stack item is always shown as the last item in the list, immediately before the
ok
prompt. In the above example, the topmost stack item is
8
.
If
showstack
has been previously executed,
noshowstack
will remove the stack display prior to each prompt.
|
Note - In some of the examples in this chapter, showstack is enabled. In those examples, each ok prompt is immediately preceded by a display of the current contents of the stack. The examples work the same if showstack is not enabled, except that the stack contents are not displayed.
|
Nearly all words that require numeric parameters fetch those parameters from the top of the stack. Any values returned are generally left on top of the stack, where they can be viewed or consumed by another command. For example, the Forth word
+
removes two numbers from the stack, adds them together, and leaves the result on the stack. In the example below, all arithmetic is in hexadecimal.
44 7 8 ok +
44 f ok +
53 ok
|
Once the two values are added together, the result is put onto the top of the stack. The Forth word
.
removes the top stack item and displays that value on the screen. For example:
53 ok 12
53 12 ok .
12
53 ok .
53
ok (The stack is now empty)
ok 3 5 + .
8
ok (The stack is now empty)
ok .
Stack Underflow
ok
|
The Stack Diagram
To aid understanding, conventional coding style requires that a
stack diagram of the form
( -- )
appears on the first line of every definition of a Forth word. The stack diagram specifies what happens to the stack with the execution of the word.
Entries to the left of
--
show stack items that are consumed (i.e. removed) from the stack and used by the operation of that word. Entries to the right of
--
show stack items that are left on the stack after the word finishes execution. For example, the stack diagram for the word
+
is:
( nu1 nu2 -- sum )
, and the stack diagram for the word
.
is:
( nu -- )
. Therefore,
+
removes two numbers (
nu1
and
nu2
), then leaves their sum (
sum
) on the stack. The word
.
removes the number on the top of the stack (nu) and displays it.
Words that have no effect on the contents of the stack (such as
showstack
or
decimal
), have a
( -- )
stack diagram.
Occasionally, a word will require another word or other text immediately following it. For example, the word
see
, used in the form
see
thisword
( -- ).
Stack items are generally written using descriptive names to help clarify correct usage. See
for stack item abbreviations used in this manual.
TABLE 4-1 Stack Item Notation
|
Notation
|
Description
|
|
|
|
Alternate stack results shown with space, e.g. ( input -- addr len false | result true ).
|
|
|
|
Alternate stack items shown without space, e.g. ( input -- addr len|0 result ).
|
|
???
|
Unknown stack item(s).
|
|
...
|
Unknown stack item(s). If used on both sides of a stack comment, means the same stack items are present on both sides.
|
|
< > <space>
|
Space delimiter. Leading spaces are ignored.
|
|
a-addr
|
Variable-aligned address.
|
|
addr
|
Memory address (generally a virtual address).
|
|
addr len
|
Address and length for memory region
|
|
byte b
xxx
|
8-bit value (low order byte in a 32-bit word).
|
|
char
|
7-bit value (low order byte), high bit unspecified.
|
|
cnt len size
|
Count or length.
|
|
d
xxx
|
Double (extended-precision) numbers. 2 stack items, hi quadlet on top of stack.
|
|
<eol>
|
End-of-line delimiter.
|
|
false
|
0 (false flag).
|
|
ihandle
|
Pointer for an instance of a package.
|
|
n n1 n2 n3
|
Normal signed values (32-bit).
|
|
nu nu1
|
Signed or unsigned values (32-bit).
|
|
<nothing>
|
Zero stack items.
|
|
phandle
|
Pointer for a package.
|
|
phys
|
Physical address (actual hardware address).
|
|
phys.lo
phys.hi
|
Lower / upper cell of physical address
|
|
pstr
|
Packed string.
|
|
quad q
xxx
|
Quadlet (32-bit value).
|
|
qaddr
|
Quadlet (32-bit) aligned address
|
|
{text}
|
Optional text. Causes default behavior if omitted.
|
|
"text<
delim
>"
|
Input buffer text, parsed when command is executed. Text delimiter is enclosed in <>.
|
|
[text<
delim
>]
|
Text immediately following on the same line as the command, parsed immediately. Text delimiter is enclosed in <>.
|
|
true
|
-1 (true flag).
|
|
u
xxx
|
Unsigned value, positive values (32-bit).
|
|
virt
|
Virtual address (address used by software).
|
|
waddr
|
Doublet (16-bit) aligned address
|
|
word w
xxx
|
Doublet (16-bit value, low order two bytes in a 32-bit word).
|
|
x x1
|
Arbitrary stack item.
|
|
x.lo x.hi
|
Low/high significant bits of a data item
|
|
xt
|
Execution token.
|
|
xxx?
|
Flag. Name indicates usage (e.g.
done?
ok?
error?
).
|
|
xyz-str xyz-len
|
Address and length for unpacked string.
|
|
xyz-sys
|
Control-flow stack items, implementation-dependent.
|
|
( C: -- )
|
Compilation stack diagram
|
|
( -- ) ( E: -- )
|
Execution stack diagram
|
|
( R: -- )
|
Return stack diagram
|
Manipulating the Stack
Stack manipulation commands (described in
) allow you to add, delete, and reorder items on the stack.
TABLE 4-2 Stack Manipulation Commands
|
Command
|
Stack Diagram
|
Description
|
|
-rot
|
( x1 x2 x3 -- x3 x1 x2 )
|
Inversely rotate 3 stack items.
|
|
>r
|
( x -- ) (R: -- x )
|
Move a stack item to the return stack. (Use with caution.)
|
|
?dup
|
( x -- x x | 0 )
|
Duplicate the top stack item if it is non-zero.
|
|
2drop
|
( x1 x2 -- )
|
Remove 2 items from the stack.
|
|
2dup
|
( x1 x2 -- x1 x2 x1 x2 )
|
Duplicate 2 stack items.
|
|
2over
|
( x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2 )
|
Copy second 2 stack items.
|
|
2rot
|
( x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2 )
|
Rotate 3 pairs of stack items.
|
|
2swap
|
( x1 x2 x3 x4 -- x3 x4 x1 x2 )
|
Exchange 2 pairs of stack items.
|
|
3drop
|
( x1 x2 x3 -- )
|
Remove 3 items from the stack.
|
|
3dup
|
( x1 x2 x3 -- x1 x2 x3 x1 x2 x3 )
|
Duplicate 3 stack items.
|
|
clear
|
( ??? -- )
|
Empty the stack.
|
|
depth
|
( -- u )
|
Return the number of items on the stack.
|
|
drop
|
( x -- )
|
Remove top item from the stack.
|
|
dup
|
( x -- x x )
|
Duplicate the top stack item.
|
|
nip
|
( x1 x2 -- x2 )
|
Discard the second stack item.
|
|
over
|
( x1 x2 -- x1 x2 x1 )
|
Copy second stack item to top of stack.
|
|
pick
|
( xu ... x1 x0 u -- xu ... x1 x0 xu )
|
Copy
u
-th stack item (
1
pick
=
over
).
|
|
r>
|
( -- x ) ( R: x -- )
|
Move a return stack item to the stack. (Use with caution.)
|
|
r@
|
( -- x ) ( R: x -- x )
|
Copy the top of the return stack to the stack.
|
|
roll
|
( xu ... x1 x0 u -- xu-1 ... x1 x0 xu )
|
Rotate
u
stack items (
2
roll
=
rot
).
|
|
rot
|
( x1 x2 x3 -- x2 x3 x1 )
|
Rotate 3 stack items.
|
|
swap
|
( x1 x2 -- x2 x1 )
|
Exchange the top 2 stack items.
|
|
tuck
|
( x1 x2 -- x2 x1 x2 )
|
Copy top stack item below second item.
|
A typical use of stack manipulation might be to display the top stack item while preserving all stack items, as shown in this example:
5 77 ok dup (Duplicates the top item on the stack)
5 77 77 ok . (Removes and displays the top stack item)
77
5 77 ok
|
Creating Custom Definitions
Forth provides an easy way to create custom definitions for new command words.
shows the Forth words used to create custom definitions.
TABLE 4-3 Color Definition Words
|
Command
|
Stack Diagram
|
Description
|
|
:
new-name
|
( -- )
|
Start a new colon definition of the word
new-name
.
|
|
;
|
( -- )
|
End a colon definition.
|
Definitions for new commands are called
colon definitions, named after the word
:
that is
used to create them. For example, suppose you want to create a new word,
add4
, that will add any four numbers together and display the result. You could create the definition as follows:
The
;
(semicolon) marks the end of the definition that defines
add4
to have the behavior (
+ + + .
). The three addition operators (
+
) reduce the four stack items to a single sum on the stack; then
.
removes and displays that result. An example follows.
ok 1 2 3 3 + + + .
9
ok 1 2 3 3 add4
9
ok
|
Definitions are stored in local memory, which means they are erased when a system resets. To keep useful definitions, put them into a text file (using a text editor under your operating system or using the NVRAMRC editor). This text file can then be loaded as needed. (See
Chapter 5
, for more information on loading files.)
When you type a definition from the User Interface, the
ok
prompt becomes a
]
(right square bracket) prompt after you type the
: (colon) and before you type the ; (semicolon). For example, you could type the definition for
add4
like this:
ok : add4
] + + +
] .
] ;
ok
|
Every definition you create (in a text file) should have a stack effect diagram shown with that definition, even if the stack effect is nil ( -- ). This is vital because the stack diagram shows the proper use of that word. Also, use generous stack comments within complex definitions; this helps trace the flow of execution. For example, when creating
add4
, you could define it as:
: add4 ( n1 n2 n3 n4 -- ) + + + . ;
|
Or you could define
add4
as follows:
: add4 ( n1 n2 n3 n4 -- )
+ + + ( sum )
.
;
|
|
Note - The ( (open parenthesis) is a Forth word meaning to ignore the following text up to ) (the closing parenthesis). Like any other Forth word, the open parenthesis must have one or more spaces following it.
|
Using Arithmetic Functions
The commands listed in
perform basic
arithmetic with items on the data stack.
TABLE 4-4 Arithmetic Functions
|
Command
|
Stack Diagram
|
Description
|
|
+
|
( nu1 nu2 -- sum )
|
Add
nu1
+
nu2
.
|
|
-
|
( nu1 nu2 -- diff )
|
Subtract
nu1
-
nu2
.
|
|
*
|
( nu1 nu2 -- prod )
|
Multiply
nu1
*
nu2
.
|
|
/
|
( n1 n2 -- quot )
|
Divide
n1
by
n2
; remainder is discarded.
|
|
/mod
|
( n1 n2 -- rem quot )
|
Remainder, quotient of
n1
/
n2
.
|
|
<<
|
( x1 u -- x2 )
|
Synonym for
lshift
.
|
|
>>
|
( x1 u -- x2 )
|
Synonym for
rshift
.
|
|
>>a
|
( x1 u -- x2 )
|
Arithmetic right-shift
x1
by
u
bits.
|
|
*/
|
( n1 n2 n3 -- quot )
|
n1
*
n2
/
n3
.
|
|
*/mod
|
( n1 n2 n3 -- rem quot )
|
Remainder, quotient of
n1
*
n2
/
n3
.
|
|
1+
|
( nu1 -- nu2 )
|
Add 1.
|
|
1-
|
( nu1 -- nu2 )
|
Subtract 1.
|
|
2*
|
( nu1 -- nu2 )
|
Multiply by 2.
|
|
2+
|
( nu1 -- nu2 )
|
Add 2.
|
|
2-
|
( nu1 -- nu2 )
|
Subtract 2.
|
|
2/
|
( nu1 -- nu2 )
|
Divide by 2.
|
|
abs
|
( n -- u )
|
Absolute value.
|
|
aligned
|
( n1 -- n1 | a-addr)
|
Round
n1
up to the next multiple of 4.
|
|
and
|
( n1 n2 -- n3 )
|
Bitwise logical
AND
.
|
|
bounds
|
( startaddr len -- endaddr startaddr )
|
Convert
startaddr
len
to
endaddr
startaddr
for
do
loop.
|
|
bljoin
|
( b.low b2 b3 b.hi -- quad )
|
Join four bytes to form a 32-bit quadword.
|
|
bwjoin
|
( b.low b.hi -- word )
|
Join two bytes to form a 16-bit word.
|
|
d+
|
(d1 d2 -- d.sum )
|
Add two 64-bit numbers.
|
|
d-
|
(d1 d2 --d.diff )
|
Subtract two 64-bit numbers.
|
|
even
|
( n -- n | n+1 )
|
Round to nearest even integer >=
n
.
|
|
fm/mod
|
( d n -- rem quot )
|
Divide
d
by n.
|
|
invert
|
( x1 -- x2 )
|
Invert all bits of
x1
.
|
|
lbflip
|
( quad1 -- quad2 )
|
Swap the bytes within a 32-bit quadword
|
|
lbsplit
|
( quad -- b.low b2 b3 b.hi )
|
Split a 32-bit quadword into four bytes.
|
|
lwflip
|
( quad1 -- quad2 )
|
Swap halves of a 32-bit quadword.
|
|
lwsplit
|
( quad -- w.low w.hi )
|
Split a 32-bit quadword into two 16-bit words.
|
|
lshift
|
( x1 u -- x2 )
|
Left-shift
x1
by
u
bits. Zero-fill low bits.
|
|
max
|
( n1 n2 -- n3 )
|
n3
is maximum of
n1
and
n2
.
|
|
min
|
( n1 n2 -- n3 )
|
n3
is minimum of
n1
and
n2
.
|
|
mod
|
( n1 n2 -- rem )
|
Remainder of
n1
/
n2
.
|
|
negate
|
( n1 -- n2 )
|
Change the sign of
n1
.
|
|
not
|
( x1 -- x2 )
|
Synonym for
invert
.
|
|
or
|
( n1 n2 -- n3 )
|
Bitwise logical OR.
|
|
rshift
|
( x1 u -- x2 )
|
Right-shift
x1
by
u
bits. Zero-fill high bits.
|
|
s>d
|
( n1 -- d1 )
|
Convert a number to a double number.
|
|
sm/rem
|
( d n -- rem quot )
|
Divide d by
n
, symmetric division.
|
|
u2/
|
( x1 -- x2 )
|
Logical right shift 1 bit; zero shifted into high bit.
|
|
u*
|
(u1 u2 -- uprod )
|
Multiply 2 unsigned numbers yielding an unsigned product.
|
|
u/mod
|
( u1 u2 -- urem uquot )
|
Divide unsigned 32-bit number by an unsigned 32-bit number; yield 32-bit remainder and quotient.
|
|
um*
|
( u1 u2 -- ud )
|
Multiply 2 unsigned 32-bit numbers; yield unsigned double number product.
|
|
um/mod
|
( ud u -- urem uprod )
|
Divide ud by
u
.
|
|
wb
flip
|
( word1 -- word2 )
|
Swap the bytes within a 16-bit word.
|
|
wbsplit
|
( word -- b.low b.hi )
|
Split 16-bit word into two bytes.
|
|
wljoin
|
( w.low w.hi -- quad )
|
Join two words to form a quadword.
|
|
xor
|
( x1 x2 --x3 )
|
Bitwise exclusive OR.
|
Accessing Memory
The User Interface provides interactive commands for examining and setting
memory. Use the User Interface to:
Memory operators let you read from and write to any memory location. All memory addresses shown in the examples that follow are virtual addresses.
A variety of 8-bit, 16-bit, and 32-bit operations are provided. In general,
a
c
(character) prefix indicates an 8-bit (one byte) operation; a
w
(word) prefix indicates a 16-bit (two byte) operation; and an l (longword) prefix indicates a 32-bit (four byte) operation.
|
Note - "l" is sometimes printed in uppercase to avoid confusion with 1 (the number one).
|
waddr
,
qaddr
, and
addr64
indicate addresses with alignment restrictions. For example,
qaddr
indicates 32-bit (4 byte) alignment; so this address must be evenly divisible by 4, as shown in the following example:
ok 4028 L@
ok 4029 L@
Memory address not aligned
ok
|
The Forth interpreter implemented in OpenBoot adheres closely to the ANS Forth Standard. If you explicitly want a 16-bit fetch or a 32-bit fetch, use
w@
or
L@
instead of
@
. Other commands also follow this convention.
lists the commands used to access memory.
TABLE 4-5 Memory Access Commands
|
Command
|
Stack Diagram
|
Description
|
|
!
|
( x a-addr -- )
|
Store a number at
a-addr
.
|
|
+!
|
( nu a-addr -- )
|
Add
nu
to the number stored at
a-addr
.
|
|
<w@
|
( waddr -- n )
|
Fetch doublet
w
from
waddr
, sign-extended.
|
|
@
|
( a-addr --x )
|
Fetch a number from
a-addr
.
|
|
2!
|
( x1 x2 a-addr -- )
|
Store 2 numbers at
a-addr
,
x2
at lower address.
|
|
2@
|
( a-addr -- x1 x2 )
|
Fetch 2 numbers from
a-addr
,
x2
from lower address.
|
|
blank
|
( addr len -- )
|
Set
len
bytes of memory beginning at
addr
to
space
(decimal 32).
|
|
c!
|
(byte addr -- )
|
Store
byte
at
addr
.
|
|
c@
|
( addr -- byte )
|
Fetch a
byte
from
addr
.
|
|
cmove
|
( addr1 addr2 u -- )
|
Copy
u
bytes from
addr1
to
addr2
, starting at low byte.
|
|
cmove>
|
( addr1 addr2 u -- )
|
Copy
u
bytes from
addr1
to
addr2
, starting at high byte.
|
|
cpeek
|
( addr -- false | byte true )
|
Fetch the byte at
addr
. Return the data and
true
if the access was successful. Return
false
if a read access error occurred.
|
|
cpoke
|
( byte addr -- okay? )
|
Store the
byte
to
addr
. Return
true
if the access was successful.
Return
false
if a write access error occurred.
|
|
comp
|
( addr1 addr2 len -- diff? )
|
Compare two byte arrays.
diff?
= 0 if arrays are identical,
diff?
= -1 if first byte that is different is lesser in string at
addr1
,
diff?
= 1 otherwise.
|
|
dump
|
( addr len -- )
|
Display
len
bytes of memory starting at
addr
.
|
|
erase
|
( addr len -- )
|
Set
len
bytes of memory beginning at
addr
to
0
.
|
|
fill
|
( addr len byte -- )
|
Set
len
bytes of memory beginning at
addr
to the value
byte
.
|
|
l!
|
( n qaddr -- )
|
Store a quadlet
q
at
qaddr
.
|
|
l@
|
( qaddr -- quad )
|
Fetch a quadlet
q
from
qaddr
.
|
|
lbflips
|
( qaddr len -- )
|
Reverse the bytes within each quadlet in the specified region.
|
|
lwflips
|
( qaddr len -- )
|
Swap the doublets within each quadlet in specified region.
|
|
lpeek
|
( qaddr -- false | quad true )
|
Fetch the 32-bit quantity at
qaddr
. Return the data and
true
if the access was successful. Return
false
if a read access error occurred.
|
|
lpoke
|
( quad qaddr -- okay? )
|
Store the 32-bit quantity at
qaddr
. Return
true
if the access was successful. Return
false
if a a write access error occurred.
|
|
move
|
( src-addr dest-addr len -- )
|
Copy
len
bytes from
src-addr
to
dest-addr
.
|
|
off
|
( a-addr -- )
|
Store
false
at
a-addr
.
|
|
on
|
( a-addr -- )
|
Store
true
at
a-addr
.
|
|
unaligned-l!
|
( quad addr -- )
|
Store a quadlet
q
, any alignment
|
|
unaligned-l@
|
( addr -- quad )
|
Fetch a quadlet
q
, any alignment.
|
|
unaligned-w!
|
( w addr -- )
|
Store a doublet
w
, any alignment.
|
|
unaligned-w@
|
( addr -- w )
|
Fetch a doublet
w
, any alignment.
|
|
w!
|
( w waddr -- )
|
Store a doublet
w
at
waddr
.
|
|
w@
|
( waddr -- w)
|
Fetch a doublet
w
from
waddr
.
|
|
wbflips
|
( waddr len -- )
|
Swap the bytes within each doublet in the specified region.
|
|
wpeek
|
( waddr -- false | w true )
|
Fetch the 16-bit quantity at
waddr
. Return the data and
true
if the access was successful. Return
false
if a read access error occurred.
|
|
wpoke
|
( w waddr -- okay? )
|
Store the 16-bit quantity to
waddr
. Return
true
if the access was successful. Return
false
if a write access error occurred.
|
The
dump
command is particularly useful. It displays a region of memory as both bytes and ASCII values. The example below displays the contents of 20 bytes of memory starting at virtual address 10000. It also shows you how to read from and write to a memory location.
ok 10000 20 dump (Display 20 bytes of memory starting at virtual address 10000)
\/ 1 2 3 4 5 6 7 8 9 a b c d e f v123456789abcdef
10000 05 75 6e 74 69 6c 00 40 4e d4 00 00 da 18 00 00 .until.@NT..Z...
10010 ce da 00 00 f4 f4 00 00 fe dc 00 00 d3 0c 00 00 NZ..tt..~\..S...
ok 22 10004 c! (Change 8-bit byte at location 10004 to 22)
ok
|
If you try (with
@
, for example) to access an invalid memory location, the operation immediately aborts and the PROM displays an error message, such as
Data
Access
Exception
or
Bus
Error
.
lists memory mapping commands.
TABLE 4-6 Memory Mapping Commands
|
Command
|
Stack Diagram
|
Description
|
|
alloc-mem
|
( size -- virt )
|
Allocate and map
size
bytes of available memory; return the virtual address.
|
|
free-mem
|
( virt size -- )
|
Free memory allocated by
alloc-mem
.
|
|
free-virtual
|
( virt size -- )
|
Undo mappings created with
memmap
.
|
The following screen is an example of the use of
alloc-mem
and
free-mem
.
An example of using
memmap
is shown below.
ok 200.0000 sbus 1000 memmap ( virt )
ok
|
Mapping An SBus Device
Here is a general method for mapping an SBus device from the
ok
prompt, without the necessity of knowing system-dependent device addresses. This method does not depend on the presence of a valid FCode PROM on the SBus device. The method will work on any OpenBoot system version 2.0 or higher.
ok " /sbus" select-dev
ok (offset) (slot#) (size) map-in ( virt )
ok
|
For example, to inspect the FCode PROM for a device in slot #3 of a system, enter:
ok " /sbus" select-dev
ok 0 3 1000 map-in .s
ffed3000
ok dup 20 dump
(Dump of first 20 bytes of FCode PROM)
ok
|
Here are some variations to the method:
-
On some systems, the pathname for the system SBus may vary. For example,
" /iommu/sbus"
(for Sun4m) or
" /io-unit/sbi"
(for Sun4d). The
show-devs
command from the
ok
prompt (which lists all system devices) is one way to determine the correct path.
-
Direct placement of (offset size) on the stack may or may not work in the most general cases on future systems. If you encounter problems, try the following, more general approach:
ok " /sbus" select-dev
ok " 3,0: decode-unit ( offset space )
ok 1000 map-in ( virt )
ok
|
Using Defining Words
The
dictionary contains all the available Forth commands. Defining words are used to create new Forth commands.
Defining words require two stack diagrams. The first diagram shows the stack effect when the new command is created. The second (or "Usage:") diagram shows the stack effect when that command is later executed.
lists the defining words that you can use to
create dictionary entries.
TABLE 4-7 Defining Words
|
Command
|
Stack Diagram
|
Description
|
|
:
name
|
( -- )
Usage: ( ??? -- ? )
|
Start creating a new colon definition.
|
|
;
|
( -- )
|
Finish creating a new colon definition.
|
|
alias
new-name
old-name
|
( -- )
Usage: ( ??? -- ? )
|
Create
new-name
with the same behavior as
old-name
.
|
|
buffer:
name
|
( size -- )
Usage: ( -- a-addr )
|
Create a named array in temporary storage.
|
|
constant
name
|
( n -- )
Usage: ( -- n )
|
Define a constant (for example,
3
constant
bar
).
|
|
2constant
name
|
( n1 n2 -- )
Usage: ( -- n1 n2 )
|
Define a 2-number constant.
|
|
create
name
|
( -- )
Usage: ( -- waddr )
|
Generic defining word.
|
|
defer
name
|
( -- )
Usage: ( ??? -- ? )
|
Define a word for forward references or execution vectors using execution token.
|
|
does>
|
( -- waddr )
|
Start the run-time clause for defining words.
|
|
field
name
|
( offset size -- offset+size )
Usage: ( addr -- addr+offset )
|
Create a named offset pointer.
|
|
struct
|
( -- 0 )
|
Initialize for
field
creation.
|
|
value
name
|
( n -- )
Usage: ( -- n )
|
Create a changeable, named 32-bit quantity.
|
|
variable
name
|
( -- )
Usage: ( -- waddr )
|
Define a variable.
|
You can use the defining word
constant
to create a name whose value will not change. A simple colon definition
: foo 22 ;
accomplishes a similar result.
ok 72 constant red
ok
ok red .
72
ok
|
value
lets you assign a name to any number. Later execution of that name leaves the assigned value on the stack. The following example assigns a value of 22 to a word named
foo
, and then calls
foo
to use its assigned value in an arithmetic operation.
ok 22 value foo
ok foo 3 + .
25
ok
|
The value can be changed with the dictionary compiling word
is
. For example:
ok 43 value thisval
ok thisval .
43
ok 10 to thisval
ok thisval .
10
ok
|
Commands created with
value
are convenient, because you do not have to use
@
every time you want the number.
The defining word
variable
assigns a name to a 32-bit region of memory, which you can use to hold values as needed. Later execution of that name leaves the address of the memory on the stack. Typically,
@
and
!
are used to read or write at that address. For example:
ok variable bar
ok 33 bar !
ok bar @ 2 + .
35
ok
|
The defining word
defer
lets you change the execution of previously defined commands, by creating a slot which can be loaded with different functions at different times. For example:
ok hex
ok defer printit
ok ['] .d to printit
ok ff printit
255
ok : myprint ( n -- ) ." It is " .h
] ." in hex " ;
ok ['] myprint to printit
ok ff printit
It is ff in hex
ok
|
Searching the Dictionary
The
dictionary
contains all the available Forth commands.
lists tools you can use to search the dictionary.
TABLE 4-8 Dictionary Searching Commands
|
Command
|
Stack Diagram
|
Description
|
|
'
name
|
( -- xt )
|
Find the named word in the dictionary.
Returns the execution token. Use outside definitions.
|
|
[']
name
|
( -- xt )
|
Similar to
'
but is used either inside or outside definitions.
|
|
.calls
|
( xt -- )
|
Display a list of all words that call the word whose execution token is
xt
.
|
|
$find
|
( addr len -- addr len false | xt n )
|
Find a word.
n
= 0 if not found,
n
= 1 if immediate,
n
= -1 otherwise.
|
|
find
|
( pstr -- pstr false | xt n )
|
Search for a word in the dictionary. The word to be found is indicated by
pstr
.
n
= 0 if not found,
n
= 1 if immediate,
n
= -1 otherwise.
|
|
see
thisword
|
( -- )
|
Decompile the named command.
|
|
(see)
|
( xt -- )
|
Decompile the word indicated by the execution token.
|
|
sift
|
( pstr -- )
|
Display names of all dictionary entries containing the string pointed to by
pstr
.
|
|
sifting
ccc
|
( -- )
|
Display names of all dictionary entries containing the sequence of characters.
ccc
contains no spaces.
|
|
words
|
( -- )
|
Display all visible words in the dictionary.
|
see
, used in the form
see
thisword
, decompiles the specified command (that is, it shows the definition used to create
thisword
). The decompiled definition may sometimes be confusing, because some internal names may have been omitted from the PROM's symbol table to save space.
The following screen is an example of how to use
sifting
.
ok sifting input
input-device input restore-input line-input input-line input-file
ok
|
words
displays all the word (command) names in the dictionary, starting with the most recent definitions.
Compiling Data into the Dictionary
The commands listed in
control the compilation of data into the dictionary.
TABLE 4-9 Dictionary Compilation Commands
|
Command
|
Stack Diagram
|
Description
|
|
,
|
( n -- )
|
Place a number in the dictionary.
|
|
c,
|
( byte -- )
|
Place a byte in the dictionary.
|
|
w,
|
( word -- )
|
Place a 16-bit number in the dictionary.
|
|
l,
|
( quad -- )
|
Place a 32-bit number in the dictionary.
|
|
[
|
( -- )
|
Begin interpreting.
|
|
]
|
( -- )
|
End interpreting, resume compilation.
|
|
allot
|
( n -- )
|
Allocate
n
bytes in the dictionary.
|
|
>body
|
( xt -- a-addr )
|
Find the data field address from the execution token.
|
|
body>
|
( a-addr -- xt )
|
Find the execution token from the data field address.
|
|
compile
|
( -- )
|
Compile next word at run time.
|
|
[compile]
name
|
( -- )
|
Compile the next (immediate) word.
|
|
forget
namep
|
( -- )
|
Remove word from dictionary and all subsequent words.
|
|
here
|
( -- addr )
|
Address of top of dictionary.
|
|
immediate
|
( -- )
|
Mark the last definition as immediate.
|
|
to
name
|
( n -- )
|
Install a new action in a
defer
word or
value
.
|
|
literal
|
( n -- )
|
Compile a number.
|
|
origin
|
( -- addr )
|
Return the address of the start of the Forth system.
|
|
patch
new-word
old-word
word-to-patch
|
( -- )
|
Replace
old-word
with
new-word
in
word-to-patch
.
|
|
(patch
|
( new-n old-n xt -- )
|
Replace
old-n
with
new-n
in word indicated
by
xt
.
|
|
recursive
|
( -- )
|
Make the name of the colon definition being compiled visible in the dictionary, and thus allow the name of the word to be used recursively in its own definition.
|
|
state
|
( -- addr )
|
Variable that is non-zero in compile state.
|
Displaying Numbers
shows basic commands to display stack values.
TABLE 4-10 Basic Number Display
|
Command
|
Stack Diagram
|
Description
|
|
.
|
( n -- )
|
Display a number in the current base.
|
|
.r
|
( n size -- )
|
Display a number in a fixed width field.
|
|
.s
|
( -- )
|
Display contents of data stack.
|
|
showstack
|
( ??? -- ??? )
|
Execute
.s
automatically before each
ok
prompt.
|
|
noshowstack
|
( ??? -- ??? )
|
Turn off automatic display of the stack before each ok prompt
|
|
u.
|
( u -- )
|
Display an unsigned number.
|
|
u.r
|
( u size -- )
|
Display an unsigned number in a fixed width field.
|
The
.s
command displays the entire stack contents without disturbing them. It can be safely used at any time for debugging purposes. (This is the function that
showstack
performs automatically.)
Changing the Number Base
You can change the operating number base using the commands in
.
TABLE 4-11 Changing the Number Base
|
Command
|
Stack Diagram
|
Description
|
|
.d
|
( n -- )
|
Display
n
in decimal without changing base.
|
|
.h
|
( n -- )
|
Display
n
in hex without changing base.
|
|
base
|
( -- addr )
|
Variable containing number base.
|
|
decimal
|
( -- )
|
Set the number base to 10.
|
|
d#
number
|
( -- n )
|
Interpret
number
in decimal; base is unchanged.
|
|
hex
|
( -- )
|
Set the number base to 16.
|
|
h#
number
|
( -- n )
|
Interpret
number
in hex; base is unchanged.
|
|
octal
|
( -- )
|
Set the number base to 16.
|
|
o#
number
|
( -- n )
|
Interpret
number
in hex; base is unchanged.
|
The
d#
,
h#
and
o#
commands are useful when you want to input a specific number in another base without explicitly changing the current base. For example:
ok decimal (Changes base to decimal)
ok 4 h# ff 17 2
4 255 17 2 ok
|
The
.d
and
.h
commands act like "
.
" but display the value in decimal or hexadecimal, respectively, regardless of the current base setting. For example:
ok hex
ok ff . ff .d
ff 255
|
Controlling Text Input and Output
This section describes
text input and output commands. These commands control strings or character arrays, and allow you to enter comments and control keyboard scanning.
lists commands to control text input.
TABLE 4-12 Controlling Text Input
|
Command
|
Stack Diagram
|
Description
|
|
(
ccc
)
|
( -- )
|
Begin a comment. Conventionally used for stack diagrams.
|
|
\
rest-of-line
|
( -- )
|
Treat the rest of the line as a comment.
|
|
ascii
ccc
|
( -- char )
|
Get numerical value of first ASCII character of next word.
|
|
expect
|
( addr +n -- )
|
Get a line of edited input from the assigned input device's keyboard; store at
addr
.
|
|
key
|
( -- char )
|
Read a character from the assigned input device's keyboard.
|
|
key?
|
( -- flag )
|
True if a key has been typed on the input device's keyboard.
|
|
span
|
( -- waddr )
|
Variable containing the number of characters read by
expect
.
|
|
word
|
( char -- pstr )
|
Collect a string delimited by
char
from input string and place in memory at
pstr
.
|
Comments are used with Forth source code (generally in a text file) to describe the function of the code. The (
(open parenthesis) is the Forth word that begins a comment. Any character up to the closing parenthesis
) is ignored by the Forth interpreter. Stack diagrams are one example of comments using (.
|
Note - Remember to follow the( with a space, so that it is recognized as a Forth word.
|
\ (backslash) indicates a comment terminated by the end of the line of text.
key
waits for a key to be pressed, then returns the ASCII value of that key on the stack.
ascii
, used in the form
ascii
x
, returns on the stack the numerical code of the character
x
.
key?
looks at the keyboard to see if the user has recently pressed any key. It returns a flag on the stack:
true
if a key has been pressed and
false
otherwise. See
Conditional Flags
for a discussion on the use of flags.
lists general-purpose
text display commands.
TABLE 4-13 Displaying Text Output
|
Command
|
Stack Diagram
|
Description
|
|
." ccc
"
|
( -- )
|
Compile a string for later display.
|
|
(cr
|
( -- )
|
Move the output cursor back to the beginning of the current line.
|
|
cr
|
( -- )
|
Terminate a line on the display and go to the next line.
|
|
emit
|
( char -- )
|
Display the character.
|
|
exit?
|
( -- flag )
|
Enable the scrolling control prompt:
More [<space>,<cr>,q] ?
The return flag is
true
if the user wants the output to be terminated.
|
|
space
|
( -- )
|
Display a
space
character.
|
|
spaces
|
( +n -- )
|
Display
+n
spaces.
|
|
type
|
( addr +n -- )
|
Display the
+n
characters beginning at
addr
.
|
cr
sends a
carriage-return character to the output. For example:
ok 3 . 44 . cr 5 .
3 44
5
ok
|
emit
displays the letter whose ASCII value is on the stack.
ok ascii a
61 ok 42
61 42 ok emit emit
Ba
ok
|
shows commands used to manipulate text strings.
TABLE 4-14 Manipulating Text Strings
|
Command
|
Stack Diagram
|
Description
|
|
",
|
( addr len -- )
|
Compile an array of bytes from
addr
of length
len
, at the top of the dictionary as a packed string.
|
|
" ccc
"
|
( -- addr len )
|
Collect an input stream string, either interpreted or compiled. Within the string,
"(00,ff...)
can be used to include arbitrary byte values.
|
|
.( ccc
)
|
( -- )
|
Display a string immediately.
|
|
-trailing
|
( addr +n1 -- addr +n2 )
|
Remove trailing spaces.
|
|
bl
|
( -- char )
|
ASCII code for the space character; decimal 32.
|
|
count
|
( pstr -- addr +n )
|
Unpack a packed string.
|
|
lcc
|
( char -- lowercase-char )
|
Convert a character to lowercase.
|
|
left-parse-string
|
( addr len char -- addrR lenR addrL lenL )
|
Split a string at
char
(which is discarded).
|
|
pack
|
( addr len pstr -- pstr )
|
Make a packed string from
addr
len
; place it at
pstr
.
|
|
"
p" ccc
|
( -- pstr )
|
Collect a string from the input stream; store as a packed string.
|
|
upc
|
( char -- uppercase-char )
|
Convert a character to uppercase.
|
Some string commands specify an address (the location in memory where the characters reside) and a length (the number of characters in the string). Other commands use a packed string or
pstr
, which is a location in memory containing a byte for the length, immediately followed by the characters. The stack diagram for the command indicates which form is used. For example,
count
converts a packed string to an address-length string.
The command
."
is used in the form:
."
string
"
. It outputs text when needed. A
"
(double quotation mark) marks the end of the text string. For example:
ok : testing 34 . ." This is a test" 55 . ;
ok
ok testing
34 This is a test55
ok
|
Redirecting Input and Output
Normally, your system uses a keyboard for all user input, and a
frame buffer with a connected display screen for most display output. (Server systems may use an ASCII terminal connected to a system serial port. For more information on how to connect a
terminal to the system unit, see your system's installation manual.) You can redirect the input, the output, or both, to either one of the system's
serial ports. This may be useful, for example, when debugging a frame buffer.
lists commands you can use to redirect input and output.
TABLE 4-15 I/O Redirection Commands
|
Command
|
Stack Diagram
|
Description
|
|
input
|
( device -- )
|
Select device (
keyboard
, or
device-specifier
) for input.
|
|
io
|
( device -- )
|
Select device for input and output.
|
|
output
|
( device -- )
|
Select device (
screen
, or
device-specifier
) for output.
|
The commands
input
and
output
temporarily change the current devices for input and output. The change occurs when you enter a command; you do not have to reset your system. A system reset or
power cycle causes the input and output devices to revert to the default settings specified in the NVRAM configuration parameters
input-device
and
output-device
. These parameters can be modified, if needed (see
Chapter 3
for information about changing defaults).
input
must be preceded by one of the following:
keyboard
,
ttya
,
ttyb
, or
device-specifier
text string. For example, if input is currently accepted from the keyboard, and you want to make a change so that input is accepted from a terminal connected to the serial port TTYA, type:
At this point, the keyboard becomes non-functional (except for
Stop-A
), but any text entered from the terminal connected to TTYA is processed as input. All commands are executed as usual.
To resume using the keyboard as the input device,
use the terminal keyboard
to type:
Similarly,
output
must be preceded by one of the following:
screen
,
ttya
, or
ttyb
. For example, if you want to send output to TTYA instead of the normal display screen, type:
The screen does
not
show the answering
ok
prompt, but the terminal connected to TTYA shows the
ok
prompt and all further output as well.
io
is used in the same way, except that it changes both the input and output to the specified place.
Generally,
input
,
output
, and
io
take a
device-specifier
, which can be either a device path name or a device alias.
The device must be specified as a Forth string, using double quotation marks
(
"
), as shown in the two examples below:
or:
In the preceding examples,
ttya
,
screen
, and
keyboard
are Forth words that put their corresponding device alias string on the stack.
Command Line Editor
OpenBoot specifies a required command
line editor (similar to EMACS, a common text editor), some optional extensions and
an optional history mechanism for the User Interface. Use these powerful tools to re-execute previous commands without retyping them, to edit the current command line to fix typing errors, or to recall and change previous commands.
lists the required line-editing commands available at the
ok
prompt.
TABLE 4-16 Required Command Line Editor Keystroke Commands
|
Keystroke
|
Description
|
|
Delete
|
Erases previous character.
|
|
Backspace
|
Erases previous character.
|
|
Control-U
|
Erases the line.
|
|
Return (Enter)
|
Finishes editing of the line and submits the entire visible line to the interpreter regardless of the current cursor position.
|
The OpenBoot standard also describes three groups of extensions of these capabilities.
lists the command line editing extension group.
TABLE 4-17 Optional Command Line Editor Keystroke Commands
|
Keystroke
|
Description
|
|
Control-B
|
Moves backward one character.
|
|
Escape B
|
Moves backward one word.
|
|
Control-F
|
Moves forward one character.
|
|
Escape F
|
Moves forward one word.
|
|
Control-A
|
Moves backward to beginning of line.
|
|
Control-E
|
Moves forward to end of line.
|
|
Delete
|
Erases previous character.
|
|
Backspace
|
Erases previous character.
|
|
Control-H
|
Erases previous character.
|
|
Escape H
|
Erases from beginning of word to just before the cursor, storing erased characters in a save buffer.
|
|
Control-W
|
Erases from beginning of word to just before the cursor, storing erased characters in a save buffer.
|
|
Control-D
|
Erases next character.
|
|
Escape D
|
Erases from cursor to end of the word, storing erased characters in a save buffer.
|
|
Control-K
|
Erases from cursor to end of line, storing erased characters in a save buffer.
|
|
Control-U
|
Erases entire line, storing erased characters in a save buffer.
|
|
Control-R
|
Retypes the line.
|
|
Control-Q
|
Quotes next character (allows you to insert control characters).
|
|
Control-Y
|
Inserts the contents of the save buffer before the cursor.
|
The command line history extension enables previously-typed commands to be saved in an EMACS-like command history ring that contains at least 8 entries. Commands may be recalled by moving either forward or backward around the ring. Once recalled, a command may be edited and/or re-submitted (by typing the Return key). The command line history extension keys are:
TABLE 4-18 Optional Command Line History Keystroke Commands
|
Keystroke
|
Description
|
|
Control-P
|
Selects and displays the previous command in the command history ring.
|
|
Control-N
|
Selects and displays the next command in the command history ring.
|
|
Control-L
|
Displays the entire command history ring.
|
The command completion extension enables the system to complete long Forth word names by searching the dictionary for one or more matches based upon the already-typed portion of a word. After you type in a portion of a word followed by the command completion keystroke,
Control-Space
, the system responds as follows:
The command completion extension keys are:
TABLE 4-19 Optional Command Completion Keystroke Commands
|
Keystroke
|
Description
|
|
Control-Space
|
Complete the name of the current word.
|
|
Control-?
|
Display all possible matches for the current word.
|
|
Control-/
|
Display all possible matches for the current word.
|
Conditional Flags
Forth conditionals use flags to indicate true/false values. A
flag can be generated in several ways, based on testing criteria. The flag can then be displayed from the stack with the word ".", or it can be used as input to a conditional control command. Control commands can cause one response if a flag is true and another if it is false. Thus, execution can be altered based on the result of a test.
A
0
value indicates that the flag value is
false
. A
-1
or any other non-zero number indicates that the flag value is
true
. (In hexadecimal, the value
-1
is displayed as
ffffffff
.)
lists commands that perform relational tests, and leave a
true
or
false
flag result on the stack.
TABLE 4-20 Comparison Commands
|
Command
|
Stack Diagram
|
Description
|
|
<
|
( n1 n2 -- flag )
|
True if
n1
<
n2
.
|
|
<=
|
( n1 n2 -- flag )
|
True if
n1
<=
n2
.
|
|
<>
|
( n1 n2 -- flag )
|
True if
n1
is not equal to
n2
.
|
|
=
|
( n1 n2 -- flag )
|
True if
n1
=
n2
.
|
|
>
|
( n1 n2 -- flag )
|
True if
n1
>
n2
.
|
|
>=
|
( n1 n2 -- flag )
|
True if
n1
>=
n2
.
|
|
0<
|
( n -- flag )
|
True if
n
< 0.
|
|
0<=
|
( n -- flag )
|
True if
n
<= 0.
|
|
0<>
|
( n -- flag )
|
True if
n
<> 0.
|
|
0=
|
( n -- flag )
|
True if
n
= 0 (also inverts any flag).
|
|
0>
|
( n -- flag )
|
True if
n
> 0.
|
|
0>=
|
( n -- flag )
|
True if
n
>= 0.
|
|
between
|
( n min max -- flag )
|
True if
min
<=
n
<=
max
.
|
|
false
|
( -- 0 )
|
The value
FALSE
, which is 0.
|
|
true
|
( -- -1 )
|
The value
TRUE
, which is -1.
|
|
u<
|
( u1 u2 -- flag )
|
True if
u1
<
u2
, unsigned.
|
|
u<=
|
( u1 u2 -- flag )
|
True if
u1
<=
u2
, unsigned.
|
|
u>
|
( u1 u2 -- flag )
|
True if
u1
>
u2
, unsigned.
|
|
u>=
|
( u1 u2 -- flag )
|
True if
u1
>=
u2
, unsigned.
|
|
within
|
( n min max -- flag )
|
True if
min
<=
n
<
max
.
|
>
takes two numbers from the stack, and returns
true
(
-1
) on the stack if the first number was greater than the second number, or returns
false
(
0
) otherwise. An example follows:
ok 3 6 > .
0 (3 is not greater than 6)
ok
|
0=
takes one item from the stack, and returns
true
if that item was 0 or returns
false
otherwise. This word inverts any flag to its opposite value.
Control Commands
The following sections describe words used within a Forth program to control the flow of execution.
The if-else-then Structure
The commands
if
,
then
and
else
provide a simple control structure.
The commands listed in
control the flow of conditional execution.
TABLE 4-21 if..else..then Commands
|
Command
|
Stack Diagram
|
Description
|
|
if
|
( flag -- )
|
Execute the following code if
flag
is
true
.
|
|
else
|
( -- )
|
Execute the following code if
if
failed.
|
|
then
|
( -- )
|
Terminate
if...else...then
.
|
The format for using these commands is:
flag if
(do this if true)
else
(do this if false)
then
(continue normally)
|
or
flag if
(do this if true)
then
(continue normally)
|
The
if
command consumes a flag from the stack. If the flag is
true
(non-zero), the commands following the
if
are performed. Otherwise, the commands (if any) following the
else
are performed.
ok : testit ( n -- )
] 5 > if ." good enough "
] else ." too small "
] then
] ." Done. " ;
ok
ok 8 testit
good enough Done.
ok 2 testit
too small Done.
ok
|
|
Note - The ] prompt reminds you that you are part way through creating a new colon definition. It reverts to ok after you finish the definition with a semicolon.
|
The case Statement
A high-level
case
command is provided for selecting alternatives with multiple possibilities. This command is easier to read than deeply-nested
if...then
commands.
lists the conditional case commands.
TABLE 4-22 case Statement Commands
|
Command
|
Stack Diagram
|
Description
|
|
case
|
( selector -- selector )
|
Begin a
case...endcase
conditional.
|
|
endcase
|
( selector | {empty} -- )
|
Terminate a
case...endcase
conditional.
|
|
endof
|
( -- )
|
Terminate an
of...endof
clause within a case...endcase
|
|
of
|
( selector test-value -- selector | {empty} )
|
Begin an
of...endof
clause within a
case
conditional.
|
Here is a simple example of a
case
command:
ok : testit ( testvalue -- )
] case 0 of ." It was zero " endof
] 1 of ." It was one " endof
] ff of ." Correct " endof
] -2 of ." It was minus-two " endof
] ( default ) ." It was this value: " dup .
] endcase ." All done." ;
ok
ok 1 testit
It was one All done.
ok ff testit
Correct All done.
ok 4 testit
It was this value: 4 All done.
ok
|
|
Note - The (optional) default clause can use the test value which is still on the stack, but should not remove it (use the phrase "dup ." instead of "."). A successful of clause automatically removes the test value from the stack.
|
The begin Loop
A
begin
loop executes the same commands repeatedly until a certain condition is satisfied. Such a loop is also called a conditional loop.
lists commands to control the execution of conditional loops.
TABLE 4-23 begin (Conditional) Loop Commands
|
Command
|
Stack Diagram
|
Description
|
|
again
|
( -- )
|
End a
begin...again
infinite loop.
|
|
begin
|
( -- )
|
Begin a
begin...while...repeat
,
begin...until
,
or
begin...again
loop.
|
|
repeat
|
( -- )
|
End a
begin...while...repeat
loop.
|
|
until
|
( flag -- )
|
Continue executing a
begin...until
loop until
flag
is true.
|
|
while
|
( flag -- )
|
Continue executing a
begin...while...repeat
loop while
flag
is true.
|
There are two general forms:
begin any commands... flag until
|
and
begin any commands... flag while
more commands repeat
|
In both cases, the commands within the loop are executed repeatedly until the proper flag value causes the loop to be terminated. Then execution continues normally with the command following the closing command word (
until
or
repeat
).
In the
begin...until
case,
until
removes a flag from the top of the stack and inspects it. If the flag is
false
, execution continues just after the
begin
, and the loop repeats. If the flag is
true
, the loop is exited.
In the
begin...while...repeat
case,
while
removes a flag from the top of the stack and inspects it. If the flag is
true
, the loop continues by executing the commands just after the
while
. The
repeat
command automatically sends control back to
begin
to continue the loop. If the flag is
false
when
while
is encountered, the loop is exited immediately; control goes to the first command after the closing
repeat
.
An easy aid to memory for either of these loops is: If true, fall through.
Here is a simple example:
ok begin 4000 c@ . key? until (repeat until any key is pressed)
43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43
ok
|
The loop starts by fetching a byte from location 4000 and displaying the value. Then, the
key?
command is called, which leaves a
true
on the stack if the user has pressed any key, and
false
otherwise. This flag is consumed by
until
and, if the value is
false
, then the loop continues. Once a key is pressed, the next call to
key?
returns
true
, and the loop terminates.
Unlike many versions of Forth, the User Interface allows the interactive use of loops and conditionals -- that is, without first creating a definition.
The do Loop
A
do
loop (also called a
counted loop)
is used when the number of iterations of the loop can be calculated in advance. A
do
loop normally exits just
before
the specified ending value is reached.
lists commands to control the execution of counted loops.
TABLE 4-24 do (Counted) Loop Commands
|
Command
|
Stack Diagram
|
Description
|
|
+loop
|
( n -- )
|
End a
do...+loop
construct; add
n
to loop index and return to
do
(if
n
< 0, index goes from
start
to
end
inclusive).
|
|
?do
|
( end start -- )
|
Begin
?do...loop
to be executed 0 or more times. Index goes from
start
to
end
-1 inclusive. If
end
=
start
, loop is not executed.
|
|
?leave
|
( flag -- )
|
Exit from a
do...loop
if
flag
is non-zero.
|
|
do
|
( end start -- )
|
Begin a
do...loop
. Index goes from
start
to
end
-1 inclusive.
Example:
10 0 do i . loop
(prints 0 1 2...d e f).
|
|
i
|
( -- n )
|
Leaves the loop index on the stack.
|
|
j
|
( -- n )
|
Leaves the loop index of the next outer enclosing loop on the stack.
|
|
leave
|
( -- )
|
Exit from
do...loop
.
|
|
loop
|
( -- )
|
End of
do...loop
.
|
This screen shows several examples of the ways in which loops are used.
ok 10 5 do i . loop
5 6 7 8 9 a b c d e f
ok
ok 2000 1000 do i . i c@ . cr i c@ ff = if leave then 4 +loop
1000 23
1004 0
1008 fe
100c 0
1010 78
1014 ff
ok : scan ( byte -- )
] 6000 5000 (Scan memory 5000 - 6000 for bytes not equal to the specified byte)
] do dup i c@ <> ( byte error? )
] if i . then ( byte )
] loop
] drop ( the original byte was still on the stack, discard it )
] ;
ok 55 scan
5005 5224 5f99
ok 6000 5000 do i i c! loop (Fill a region of memory with a stepped pattern)
ok
ok 500 value testloc
ok : test16 ( -- ) 1.0000 0 ( do 0-ffff ) (Write different 16-bit values to a location)
] do i testloc w! testloc w@ i <> ( error? ) (Also check the location)
] if ." Error - wrote " i . ." read " testloc w@ . cr
] leave ( exit after first error found ) (This line is optional)
] then
] loop
] ;
ok test16
ok 6000 to testloc
ok test16
Error - wrote 200 read 300
ok
|
Additional Control Commands
contains descriptions of additional program execution control commands.
TABLE 4-25 Program Execution Control Commands
|
Command
|
Stack Diagram
|
Description
|
|
abort
|
( -- )
|
Abort current execution and interpret keyboard commands.
|
|
abort
"
ccc
"
|
( abort? -- )
|
If
abort?
is true, abort and display message.
|
|
eval
|
( addr len -- )
|
Interpret Forth source from an array.
|
|
execute
|
( xt -- )
|
Execute the word whose execution token is on the stack.
|
|
exit
|
( -- )
|
Return from the current word. (Cannot be used in counted loops.)
|
|
quit
|
( -- )
|
Same as
abort
, but leave stack intact.
|
abort
causes immediate termination and returns control to the keyboard.
abort"
is similar to
abort
but is different in two respects.
abort"
removes a flag from the stack and only aborts if the flag is
true
. Also,
abort"
prints any desired message when the abort takes place.
eval
takes a string from the stack (specified as an address and a length). The characters in that string are then interpreted as if they were entered from the keyboard. If a Forth text file has been loaded into memory (see
Chapter 5
, then
eval
can be used to compile the definitions contained in the file.