11 FCode Dictionary





This dictionary describes all of the FCodes defined by IEEE Standard 1275-1994 and supported in the 3.x tokenizer. This dictionary includes the pre-defined FCode words that you can use as part of FCode source code programs. It also includes tokenizer directives and macros. Appendix A, "FCode Reference", contains a command summary, with words grouped by function.

The words are listed alphabetically in this chapter, sorted by the first alphabetic character in the word's name. For example, the words mod and */mod are adjacent to each other. Words having no alphabetic characters in their names are placed at the beginning of the chapter, in ASCII order.

The boot PROM and tokenizer are case-insensitive (all Forth words are converted to lowercase internally). The only exceptions are literal text, such as text inside " strings and text arguments to the ascii command, which are left in the original form. In general, you may use either uppercase or lowercase. By convention, OpenBoot drivers are written in lowercase.

Defining words create a header by calling external-token, named-token, or new-token. See the definitions of these words for more details.

All FCode byte values listed in this chapter are in hexadecimal.

!
( x a-addr -- )

Stores x at a-addr. For more portable code, use l! if you explicitly want a 32-bit access. a-addr must be aligned as given by variable.

See also: c!, w!, l!, rb!, rw!, rl!

( [text<"< ] -- text-str text-len ) 12 len xx xxxx ... b(") len-byte xx-byte ... xx-byte

Gathers the immediately following text string or hex data until reaching the terminator "<whitespace>.

At execution time, the address and length of the string is left on the stack. For example:

-----------------------------------------------------
" SUNW,new-model" encode-string " model" property -----------------------------------------------------

You can embed control characters and 8-bit binary numbers in strings. This is similar in principle to the \n convention in C, but syntactically tuned for Forth. This feature applies to the string arguments of the words " and ."

The escape character is `"'. Here is the list of escape sequences:

    Table 11-1 Escape Sequences in Text Strings

--------------------------------------------------------------------------------------------------
Function Syntax --------------------------------------------------------------------------------------------------
          
""        quote (")
          
"n        newline
          
"r        carriage return
          
"t        tab
          
"f        formfeed
          
"l        linefeed
          
"b        backspace
          
"!        bell
          
"^x       control x, where x is any printable character
          
"(hh hh)  Sequence of bytes, one byte for each pair of hex digits hh . Non-hex characters will 
          be ignored

--------------------------------------------------------------------------------------------------

" followed by any other printable character not mentioned above is equivalent to that character.

"(means to start parsing pairs of hexadecimal digits as one or more 8-bit characters in the range 0x00 through 0xFF, delimited by a trailing) and ignoring non-hexadecimal digits between pairs of hexadecimal digits. Both uppercase and lowercase hexadecimal digits are recognized. Since non-hex characters (such as space or comma) are ignored between "(and), these characters make useful delimiters.

Any characters thus recognized are appended to any previous text in the string being assembled. After the ) is recognized, text assembly continues until a trailing "<whitespace'>.

For example:

------------------------------------------------------------------------------
" This is "(01 32,8e)abc"nA test xyzzy "!"! abcdefg""hijk"^bl" ^^^^^^ ^ ^ ^ ^ ^ 3 bytes newline 2 bells " control b ------------------------------------------------------------------------------

Note - The use of "n for line breaks is discouraged. The preferred method is to use cr, rather than embedding the line break character inside a string. Use of cr results in more accurate display formatting, because Forth updates its internal line counter when cr is executed.

When " is used outside a colon definition, only two interpreted strings of up to 80 characters each can be assembled concurrently. This limitation does not apply in colon definitions.

See also: b(")

#
( ud1 -- ud2 ) C7

Converts a digit ud1 in pictured numeric output conversion. Typically used between <# and #'>.

#'>
( ud -- str len ) C9

Ends pictured numeric output conversion. str is the address of the resulting output array. len is the number of characters in the output array. str and len together are suitable for type. See (.) and (u.) for typical usages.

( "old-name< " -- xt ) code: " FCode (name) generates: b(`) old-FCode#

Generates the execution token (xt) of the word immediately following ' in the input stream. ' should only be used outside of definitions. See b('), ['] for more details.

For example:

------------------------------------------
defer opt-word ( -- ) ' noop is opt-word ------------------------------------------
(
( [text<) -- ) code: none

Causes the compiler/interpreter to ignore subsequent text after the "( " up to a delimiting ")" . Note that a space is required after the (. Although either ( or \ may be used equally well for documentation, by common convention we use ( ...) for stack comments and \ ... for all other text comments and documentation.

For example:

-------------------------------------
: 4drop ( a b c d -- ) 2drop ( a b ) 2drop ( ) ; -------------------------------------
(.)
( n -- str len ) code: 47 2d 96 9a 49 98 97 generates: dup abs <# u#s swap sign u#'>

Converts a number into a text string according to the value in base.This is the numeric conversion primitive, used to implement display words such as "." If n is negative, the first character in the array will be a minus (-) sign.

For example:

------------------------------------------------------------
" CPU boot: show-version ( -- ) .rom version is " base @ d# 16 base ! ( old-base ) firmware-version ( old-base version ) lwsplit (.) type ascii . emit .h cr base ! ( ) ------------------------------------------------------------
*
( nu1 nu2 -- prod ) 20

prod is the arithmetic product of nu1 times nu2. If the result cannot be represented in one stack entry, the least significant bits are kept.

*/
( n1 n2 n3 -- quot ) 30 20 31 21

Calculates n1*n2/n3.

+
( nu1 nu2 -- sum ) 1E

sum is the arithmetic sum of nu1 plus nu2.

+!
( nu a-addr -- ) 6C

nu is added to the value stored at a-addr. This sum replaces the original value at a-addr. a-addr must be aligned as given by variable.

,
( x -- ) D3

Reserves one cell of storage in data-space and stores x in the cell.The data space pointer must be aligned prior to the execution of ,.

For example, to create an array containing integers 40004000 23 45 6734:

-----------------------------------------------
create my-array 40004000 , 23 , 45 , 6734 , -----------------------------------------------
-
( nu1 nu2 -- diff ) 1F

diff is the result of subtracting nu1 minus nu2.

( nu -- ) 9D

Displays the absolute value of nu in a free field format with a leading minus sign if nu is negative, and a trailing space.

If the base is hexadecimal, . displays the number in unsigned format, since signed hex display is hardly ever wanted. Use s. to display signed hex numbers.

See also: s.

."
( [text<"] -- ) 12 len xx xx ... 90 b(") len text type

This word compiles a text string, delimited by "<whitespace'> e.g. .
" hello world"
.

At execution time, the string is displayed. This word is equivalent to using
" text" type .

." is normally used only in a definition. The text string will be displayed later when that definition is called. You may wish to follow it with cr to flush out the text buffer immediately. Use .( for any printing to be done immediately.

See also: ", .(, tokenizer[

.(
( [text<)] -- ) 12 len xx xx ... 90

Gathers a text string, delimited by ) , to be immediately displayed. For example:

-----------------
.( hello world) -----------------

This word is equivalent to: " text" type

Use .( to print out text immediately. (You may wish to follow it with a cr to flush out the text buffer immediately). .( may be called either inside or outside of definitions; the text is immediately displayed in either case.

Note that during FCode interpretation the string will typically be printed out of serial port A, since any frame buffer present may not yet be activated when SBus slots are being probed. Use ." for any printing to be done when new words are later executed.

See also .", tokenizer[

/
( n1 n2 -- quot ) 21

Calculates n1 divided by n2. An error condition results if the divisor (n2) is zero. See /mod.

:
( "new-name< " -- colon-sys ) (E: ... -- ??? ) (header) b7 new-token|named-token|external-token b(:)

Begins a new definition, terminated by ; Used in the form:

------------------
: my-newname ... ; ------------------

Later usage of my-newname is equivalent to usage of the contents of the definition.

See named-token, new-token, and external-token for more information on header formats.

;
( colon-sys -- ) C2 b(;)

Ends the compilation of a colon definition.

See also: :

<
( n1 n2 -- less_than? ) 3A

less_than? is true if n1 is less than n2. n1 and n2 are signed integers.

<#
( -- ) 96

Initializes pictured numeric output conversion. You can use the words:

----------------------------
<# # #s hold sign #'> ----------------------------

to specify the conversion of a number into an ASCII character string stored in right-to-left order. See (.) and (u.) for example usages.

<<
( x1 u -- x2 ) 27 lshift

x2 is the result of logically left shifting x1 by u places. Zeroes are shifted into the least-significant bits.

For example:

-----------------------------------------------------------------
: bljoin ( byte.low byte.lowmid byte.highmid byte.high -- l ) 8 << + 8 << + 8 << + ; -----------------------------------------------------------------
<=
( n1 n2 -- less_than_or_equal? ) 43

less_than_or_equal? is true if n1 is less than or equal to n2. n1 and n2 are signed integers.

<'>
( x1 x2 -- not_equal? ) 3D

not_equal? is true if x1 is not equal to x2. x1 and x2 are signed integers.

=
( x1 x2 -- equal? ) 3C

equal? is true if x1 is equal to x2. x1 and x2 are signed integers.

>
( n1 n2 -- greater_than? ) 3B

greater_than? is true if n1 is greater than n2. n1 and n2 are signed integers.

>=
( n1 n2 -- greater_than_or_equal? ) 42

greater_than_or_equal? is true if n1 is greater than or equal to n2. n1 and n2 are signed integers.

>'>
( x1 u -- x2 ) 28 rshift

x2 is the result of logically right shifting x1 by u places. Zeroes are shifted into the most-significant bits. Use >a for signed shifting.

For example:

----------------------------------
: wbsplit ( w -- b.low b.high ) dup h# ff and swap 8 > h# ff and ; ----------------------------------
?
( a-addr -- ) 6d 96 @ .

Fetches and prints the value at the given address. A standard Forth word, primarily used interactively.

@
( a-addr -- x ) 6D

x is the value stored at a-addr. a-addr must be aligned as given by variable.

See also: c@, w@, l@, rb@, rw@, rl@

[
( -- ) none

Enter interpretation state.

[']
( [old-name< ] -- xt ) 11 FCode b(') old- FCode#

' or ['] is used to generate the execution token (xt) of the word immediately following the ' or ['].

' should only be used outside definitions; ['] may be used either inside or outside definitions. Examples shown usually use ['], since it will always generate the intended result:

-----------------------------------------
: my-probe ... ['] my-install is-install ... ; -----------------------------------------

or

------------------------
['] my-install is-install ------------------------

In normal Forth, ' may be used in definitions for the creation of language extensions, but such usage is not applicable to FCode Programs.

\
( [rest-of-line<eol -- ) none

Causes the compiler/interpreter to ignore the rest of the input line after the \ . \ can occur anywhere on an input line. Note that a space must be present after \ .

For example:

--------------------------------------------------
0 value his-ihandle \ place to save someone's ihandle --------------------------------------------------

See also: (, (s

]
( -- ) none

Enter compilation state.

0
( -- 0 ) A5

Leaves the value 0 on the stack. The only numbers that are not encoded using b(lit) are the values -1, 0, 1, 2, or 3. Because these numbers occur so frequently, they are assigned individual FCodes to save space.

0<
( n -- less_than_0? ) 36

less_than_0? is true if n is less than zero (negative).

0<=
( n -- less_than_or_equal_to_0? ) 37

less_than_or_equal_to_0? is true if n is less than or equal to zero.

0<'>
( n -- not_equal_to_0? ) 35

not_equal_to_0? is true if n is not zero.

0=
( n -- equal_to_0? ) 34

equal_to_0? is true if n is zero. This word will invert any flag.

0'>
( n -- greater_than_0? ) 38

greater_than_0? is true if n is greater than zero.

0=
( n -- greater_than_or_equal_to_0? ) 39

greater_than_or_equal_to_0? is true if n is greater than or equal to zero.

1
( -- 1 ) A6

Leaves the value 1 on the stack. The only numbers that are not encoded using b(lit) are the values -1, 0, 1, 2, or 3. Because these numbers occur so frequently, these values are assigned individual FCodes to save space.

1+
( nu1 -- nu2 ) A6 1E generates: 1 +

nu2 is the result of adding 1 to nu1.

1-
( nu1 -- nu2 ) A6 1F 1 -

nu2 is the result of subtracting 1 from nu1.

-1
stack: ( -- -1 ) A4

Leaves the value -1 on the stack. The only numbers that are not encoded using b(lit) are the values -1, 0, 1, 2, or 3. Because these numbers occur so frequently, these values are assigned individual FCodes to save space.

2
( -- 2 ) A7

Leaves the value 2 on the stack. The only numbers that are not encoded using b(lit) are the values -1, 0, 1, 2, or 3. Because these numbers occur so frequently, these values are assigned individual FCodes to save space.

2!
( x1 x2 a-addr -- ) 77

x1 and x2 are stored in consecutive locations starting at a-addr. x2 is stored at the lower address. This is equivalent to: swap over ! cell+ ! .

2*
( x1 -- x2 ) 59

x2 is the result of shifting x1 left one bit. A zero is shifted into the vacated bit position. This is equivalent to multiplying by 2.

2+
( nu1 -- nu2 ) A7 1E 2 +

nu2 is the result of adding 2 to nu1.

2-
( nu1 -- nu2 ) A7 1F 2 -

nu2 is the result of subtracting 2 from nu1.

2/
( x1 -- x2 ) 57

x2 is the result of arithmetically shifting x1 right one bit. The sign is included in the shift and remains unchanged. This is equivalent to dividing by 2.

2@
( a-addr -- x1 x2 ) 76

x1 and x2 are two numbers stored in consecutive 32-bit locations starting at a-addr. x2 is the number that was stored at the lower address. This is equivalent to: dup cell+ @ swap @ .

3
( -- 3 ) A8

Leaves the value 3 on the stack. The only numbers that are not encoded using b(lit) are the values -1, 0, 1, 2, or 3. Because these numbers occur so frequently, these values are assigned individual FCodes to save space.

>a
( x1 u -- x2 ) 29

x2 is the result of arithmetically right shifting x1 by u places. The sign bit of x1 is shifted into the most-significant bits (i.e. sign extend the high bit).

For example:

--------------------
ok ffff.0000 6 >a .h fffffc00 ok ffff.0000 6 > .h 3fffc00 --------------------
abort
( ... -- ) (R: ... -- ) 2 16

Aborts program execution, clearing the data and return stacks. Control returns to the ok prompt. Called after encountering fatal errors.

For example:

---------------------------------------------------------
: probe-loop ( addr -- ) begin dup l@ drop key? if abort then again \ generate a tight probe loop until any key is pressed. ; ---------------------------------------------------------
abort"
(C: [text<"] -- ) ( ... abort? -- ... | <nothing) (R: ... -- ... | <nothing) none

If abort? is non-zero, display text and call abort. Leading spaces in text are not ignored and end-of-line is not treated as a delimiting space.

abs
( n -- u ) 2D

u is the absolute value of n. If n is the maximum negative number, u is the same value since the maximum negative number in two's complement notation has no positive equivalent.

accept
( addr len1 -- len2 ) none generates: span @ -rot expect span @ swap span !

Get an edited input line, storing it at addr.

again
( C: dest-sys -- ) ( -- ) 13 offset

Used in the form begin...again to generate an infinite loop. Use a keyboard abort, or abort or exit, to terminate such a loop. Use this word with caution!

For example:

---------------------------------------------------------
: probe-loop ( addr -- ) \ generate a tight probe loop until any key is pressed. begin dup l@ drop key? if abort then again ; ---------------------------------------------------------

See also: repeat, until, while

alarm
( xt n -- ) 2 13

Arranges to execute the package method xt at periodic intervals of n milliseconds (to the best accuracy possible). If n is 0, stop the periodic execution of xt in the current instance context (leaving unaffected any periodic execution of xt that was established in a different instance).

xt is the execution token, as returned by [']. Each time the method is called, the current instance will be set to the same as the current instance at the time that alarm was executed and the current instance will then be restored to its previous value afterwards.

xt must be the execution token of a method which neither expects stack arguments nor leaves stack results i.e. whose stack diagram is ( -- ).

A common use of alarm would be to implement a console input device's polling function.

For example:

-----------------------------------------------------------------
: my-checker ( -- ) test-dev-status if user-abort then ; : install-abort ( -- ) ['] my-checker d# 10 alarm ; -----------------------------------------------------------------
alias
( "new-name< old-name< " -- ) none

alias creates a new name, with the exact behavior of some other existing name. The new name can then be used interchangeably with the old name and have the same effect.

The tokenizer does not generate any FCode for an alias command, but instead simply updates its own lookup table of existing words. Any occurrence of new-name causes the assigned FCode value of old-name to be generated. One implication is that new-name will not appear in the OpenBoot dictionary after the FCode Program is compiled. If this behavior is undesirable, use a colon definition instead.

If the original FCode source text is downloaded and interpreted directly, without being tokenized or detokenized, then any new alias words will show up and be usable directly.

For example:

-------------------------------------
alias pkg-prop get-package-property -------------------------------------
align
( -- ) none

Allocates dictionary bytes as necessary to leave the top of the dictionary variable aligned.

aligned
( n1 -- n1 | a-addr ) AE

Increases n1 as necessary to yield a variable aligned address. If n1 is already aligned, returns n. Otherwise, returns the next higher variable aligned address, a-addr.

alloc-mem
( len -- a-addr ) 8B

Allocates a buffer of len of physical memory that has been aligned to the most stringent requirements of the processor. If successful, returns the associated virtual address. If not successful, throw will be called with an appropriate error message as with abort".

Memory allocated by alloc-mem is not suitable for DMA.

See also: abort", dma-alloc, free-mem, throw.

To detect an out-of-memory condition:

---------------------------------
h# 100 ['] alloc-mem catch ?dup if throw else ( virt ) constant my-buff then ---------------------------------
allot
( len -- ) none generates: 0 max 0 ?do 0 c, loop

Allocates len bytes in the dictionary. If the operation fails, a throw will be called with an appropriate error message as with abort". Error conditions can be detected and handled properly with the phrase ['] allot catch.

and
( x1 x2 -- x3 ) 23

x3 is the bit-by-bit logical and of x1 with x2.

ascii
( [text< ] -- char ) 10 00 00 00 xx b(lit) 00 00 00 value

Skips leading space delimiters and puts the ASCII value of the first letter in text on the stack. For example:

---------------------------
ascii C ( equals hex 43 ) ascii c ( equals hex 63 ) ---------------------------
b(")
( -- str len ) len xx xx xx ...

An internal word, generated by ", ." and .( which leaves a text string on the stack. Never use the word b(") in source code.

b(')
( -- xt ) FCode#

An internal word, generated by ' and ['] which leaves the execution token of the immediately following word on the stack. The FCode for b(') should always be followed by the FCode of the desired word. Never use the word b(') in source code.

b(:)
( -- ) B7

An internal word generated by the defining word : . Never use the word b(:) in source code.

b(;)
( -- ) C2

An internal word generated by ; to end a colon definition. Never use the word b(;) in source code.

base
( -- addr ) A0

base is the variable that contains the current numeric conversion radix to be used when the FCode Program is executing, such as 10 for decimal, 16 for hex, 8 for octal, and so on. Like any variable, base leaves its address on the stack.

For example, to print the current value of base, use:

-----------
base @ .d -----------

The tokenizer words decimal or hex are also available for changing the value in base as desired. However, these words behave differently depending whether they occur in a definition or outside of a definition.

If decimal or hex occur in a definition, then it will be compiled, later causing a change to the value in base when that definition is executed.

If decimal or hex occur outside of a definition, however, then it is interpreted as a command to the tokenizer program itself, thus affecting the interpretation of all subsequent numbers in the text.

Note that changes to base affect the numeric base of the User Interface, which can create much confusion for any user (the default value for base is hexadecimal). If you must change the base, it is recommended that you save and then restore the original base, as in:

--------------------------------
: .o ( n -- ) \ Print n in octal base @ swap ( oldbase n ) 8 base ! ( oldbase ) base ! --------------------------------

In general, only numeric output will be affected by the value in base. Fixed numbers in FCode source are interpreted by the tokenizer program. Most numeric input is controlled by decimal, hex, d#, and h#, but these words only affect the tokenizer input base; they but do not affect the value in base.

For example:

-----------------------------------------------------------------------------------------
( assume the initial value in base is 16, i.e. User Interface is in hex ) ( no assumptions should be made about the initial tokenizer base ) version1 hex ( tokenizer in base 16; later execution, using base, in base 16 ) 20 . ( compile decimal 32, later print "20" when FCode executes ) decimal ( tokenizer is in base 10, later execution is in base 16 ) 20 . ( compile decimal 20, later print "14" since FCode executes in hex ) : TEST ( -- ) 8base !( still compiling in decimal, later change base when TEST executes ) 20 . ( compiles decimal 20, prints "24" since base was just changed ) h# 20 .d ( compiles decimal 32, prints "32"; no permanent base changes ) 20 . ( compiles decimal 20, prints "24" ) ; 20 . ( compile decimal 20, later print "14" ) TEST ( prints "24 32 24"; has a side-effect of changing the base ) 20 . ( compile decimal 20, later print 24 since TEST changed base ) hex ( tokenizer is in base 16; later execution, using base, still in base 8 ) 20 . ( compile decimal 32, later print "40" ) -----------------------------------------------------------------------------------------

If this all seems confusing, simply follow these guidelines:

Good: Initially declare hex just after fcode-version2, and make liberal use of d#, h#, .h and.d.

Bad: Changing base either directly or by calling decimal or hex in a definition.

bbranch
( -- ) 13 offset

An internal word generated by again, repeat, and else which causes an unconditional branch. Never use the word bbranch in source code.

b?branch
( flag -- ) 14 offset

An internal word generated by until, while, and if which causes a conditional branch. Never use the word b?branch in source code.

b(buffer:)
( n -- ) BD

An internal word generated by the defining word buffer: which allocates n bytes of storage space. Never use the word b(buffer:) in source code.

b(case)
( sel-- sel ) C4

An internal word generated by case. Never use the word b(case) in source code.

b(constant)
( n -- ) BA

An internal word generated by the defining word constant. Never use the word b(constant) in source code.

b(create)
( -- ) BB

An internal word generated by the defining word create. Never use the word b(create) in source code.

b(defer)
( -- ) BC

An internal word generated by the defining word defer. Never use the word b(defer) in source code.

b(do)
( end start -- ) 17 +offset

An internal word generated by do. Never use the word b(do) in source code.

b(?do)
( end start -- ) 18 +offset

An internal word generated by ?do. Never use the word b(?do) in source code.

begin
( C: -- dest-sys ) ( -- ) b1 b(<mark)

Marks the beginning of a conditional loop, such as begin...until, begin...while... repeat, or begin...again. See these other words for more details.

behavior
( defer-xt -- contents-xt ) DE

This command is used to retrieve the execution contents of a defer word.

A typical use would be to fetch and save the current execution of a defer word, change the behavior temporarily and later restore the original behavior. For example:

-------------------------------
defer my-func 0 value old-func ['] framus is my-func ... ['] my-func behavior is old-func ['] foo is my-func ... my-func ... old-func is my-func -------------------------------
bell
( -- 0x07 ) AB

Leave the ASCII code for the bell character on the stack.

b(endcase)
( sel | <nothing-- ) C5

An internal word generated by endcase. Never use the word b(endcase) in source code.

b(endof)
( -- ) C6

An internal word generated by endof. Never use the word b(endof) in source code.

between
( n min max -- min<=n<=max? ) 44

min<=n<=max? is true if n is between min and max, inclusive of both endpoints.

See within for a different form of comparison.

b(field)
( addr -- addr+offset ) BE

An internal word generated by the defining word field. Never use the word b(field) in source code.

bl
( -- 0x20 ) A9

Leaves the ASCII code for the space character on the stack.

blank
( addr len -- ) A9 79 generates: bl fill

Sets len bytes of memory beginning at addr to the ASCII character value for space (hex 20). No action is taken if len is zero.

b(leave)
( -- ) 1B

An internal word generated by leave. Never use the word b(leave) in source code.

blink-screen
( -- ) 1 5B

A defer word, called by the terminal emulator, when it has processed a character sequence that calls for ringing the console bell, but the console input device package has no ring-bell method.

blink-screen is initially empty, but must be loaded with a system-dependent routine in order for the terminal emulator to function correctly. The routine must cause some momentary discernible effect that leaves the screen in the same state as before.

This can be done with to, or it can be loaded automatically with fb1-install or fb8-install (which loads fb1-blink-screen or fb8-blink-screen, respectively). These default routines invert the screen (twice) by xor-ing every visible pixel. This is quite slow.

A replacement routine simply disables the video for 20 milliseconds or so, i.e.

-------------------------------------------------------------
: my-blink-screen ( -- ) video-off 20 ms video-on ; ... \ load default behaviors with fbx-install, then: ['] my-blink-screen to blink-screen -------------------------------------------------------------

Of course, this example assumes that your display hardware is able to quickly enable and disable the video without otherwise affecting the state.

b(lit)
( -- n ) 10 xx xx xx xx

An internal word used to save numbers. Never use the word b(lit) in source code.

The only numbers that are not encoded using b(lit) are the values -1, 0, 1, 2, or 3. Because these numbers occur so frequently, these values are assigned individual FCodes to save space.

bljoin
( byte.lo byte2 byte3 byte.hi -- quad ) 7F

Merges four bytes into a single 32-bit word. Incorrect results may be generated unless the high bytes of each input stack item are zero.

b(loop)
( -- ) 15 -offset

An internal word generated by loop. Never use the word b(loop) in source code.

b(+loop)
( n -- ) 16 -offset

An internal word generated by +loop. Never use the word b(+loop) in source code.

b(<mark)
( -- ) B1

An internal word generated by begin. Never use the word b(<mark) in source code.

body'>
( a-addr -- xt ) 85

Converts the data field address of a word to its execution token.

>body
( xt -- a-addr ) 86

Converts the execution token of a word to its data field address.

b(of)
( testval -- ) 1C +offset

An internal word generated by of. Never use the word b(of) in source code.

bounds
( start cnt -- start+cnt start ) AC

Converts a starting value and count into the form required for a do or ?do loop. For example, to perform a loop 20 times, counting up from 4000 to 401f inclusive, use:

------------------------
4000 20 bounds do...loop ------------------------

This is equivalent to:

-------------------
4020 4000 do...loop -------------------
b(resolve)
( -- ) B2

An internal word generated by repeat and then. Never use the word b(resolve) in source code.

bs
( -- 0x08 ) AA

Leaves the ASCII code for the backspace character on the stack.

b(to)
( -- ) C3

An internal word generated by to. Never use the word b(to) in source code.

buffer:
( len "new-name< " -- ) (E: -- addr ) (header) new-token|named-token|external-token b(buffer:)

Allocates len bytes of storage space and creates a name, new-name. When new-name is executed, it leaves the address of the first byte of the buffer on the stack.

For example:

------------------
200 buffer: name name ( addr ) ------------------
b(value)
( n -- ) B8

An internal word generated by the defining word value. Never use the word b(value) in source code.

b(variable)
( n -- ) B9

An internal word generated by the defining word variable. Never use the word b(variable) in source code.

bwjoin
( byte.lo byte.hi -- w ) B0

Merges two bytes into the low 16-bits of a stack entry whose upper bytes are zeroed. Incorrect results may be generated unless the high bytes of each input stack item are zero.

byte-load
( addr xt -- ) 2 3E

Interprets the FCode Program located at addr. If xt is 1, use rb@ to read the FCode Program, otherwise use xt as the execution token of the definition to be used to read the FCode Program. Continue reading and interpreting the program until end0 is encountered.

Be aware that byte-load does not itself create a new device node as a "container" for any properties and methods defined by the FCode Program that byte-load evaluates. If the FCode Program is intended to create such a node, appropriate preparation must be done before and after executing byte- load. For example, new-device and set-args can be executed before and finish-device can be executed after byte-load is executed.

If byte-load is to be executed from the User Interface, additional set up is usually necessary before executing new-device.

c!
( x addr -- ) 75

Stores the least significant 8 bits of x in the byte at addr.

See also: rb!

c,
( byte -- ) D0

Compiles a byte into the dictionary. c, can be used, in conjunction with create, to create an array-type structure, as:

------------------------------------------------------
create yellow 77 c, 23 c, ff c, ff c, 47 c, 22 c, ... ------------------------------------------------------

Later execution of yellow leaves the address of the first byte of the array (the address of the byte "77") on the stack.

/c
( -- n ) 5A

Leaves the number of address units to a byte (i.e. 1) on the stack.

See also: /w, /l, /n

/c*
( nu1 -- nu2 ) 66 chars

Synonym for chars.

c@
( addr -- n ) 71

Fetches the byte at address addr and leaves it on top of the stack with the high order bytes filled with zeroes.

See also: rb@

ca+
( addr1 index -- addr2 ) 5E

Increments addr1 by index times the value of /c. ca+ should be used in preference to + when calculating addresses because it more clearly expresses the intent of the operation and is more portable.

ca1+
( addr1 -- addr2 ) 62 char+

Synonym for char+

$call-method
( ??? method-str method-len ihandle -- ??? ) 2 0E

Executes the device interface method method-str method-len in the open package instance ihandle. The question marks (???) indicate that the contents of the stack before and after the method is called depend on the particular method being called.

For example:

---------------------------------------------------------------------------
: dma-alloc ( #bytes -- vaddr ) " dma-alloc" my-parent $call-method ; ---------------------------------------------------------------------------

See also: open-package.

call-package
( ??? xt ihandle -- ??? ) 2 08

Executes the device interface method xt in the open package instance ihandle. The question marks (???) indicate that the contents of the stack before and after the method is called depend on the particular method being called.

For example:

------------------------------------------------------------------
0 value label-ihandle \ place to save the ihandle of other package 0 value offset-method \ place to save the xt of found method : init ( -- ) my-args " disk-label" $open-package ( ihandle ) to label-ihandle " offset" label-ihandle ihandlephandle ( name-addr name-len phandle ) find-method if to offset-method else ." Can't find offset method " then ; init : add-offset ( d.byte# -- d.bytes# ) offset-method label-ihandle call-package ; ------------------------------------------------------------------

See also: find-method, open-package

$call-parent
( ??? method-str method-len -- ??? ) 2 09

Calls the method named by method-str method-len in the parent instance. If the called package has no such method, an error is signaled with throw. Equivalent to:

--------------------------
my-parent $call-method --------------------------

The question marks (???) indicate that the contents of the stack before and after the method is called depend on the particular method being called.

For example:

-------------------------------------------------------------------
: my-dma-alloc ( -- vaddr ) h# 2000 " dma-alloc" $call-parent ; -------------------------------------------------------------------
carret
( -- 0x0D ) 10 00 00 00 0D b(lit) 00 00 00 0x0D

Leaves the ASCII code for "carriage return" on the stack.

case
( sel -- sel ) C4 generates: b(case)

Starts a case statement that selects its action based on the value of sel. Example of use:

----------------------------------------------------
: foo ( selector -- ) case 0 of ." It was 0" endof 5 of ." It was 5" endof -2 of ." It was -2" endof ( selector ) ." It was " dup u. \ default clause endcase ; ----------------------------------------------------

of tests the top of the stack against the selector at run time. If they are the same, the selector is dropped and the following Forth code is executed. If they are not the same, execution continues at the point just following the matching endof.

The default clause is optional. When an of clause is executed, the selector is not on the stack. When a default clause is executed, the selector is on the stack. The default clause may use the selector, but must not remove it from the stack (it will be automatically removed by endcase). If the default case adds to the stack, the selector must be moved to top of stack from which it will be dropped. For example:

----------------------------
: bar (selector -- value ) case 3 of 21 endof 4 of 33 endof 27 swap \ default clause endcase ; ----------------------------

case statements can be used both inside and outside of colon definitions.

catch
( ??? xt -- ??? error-code | ??? false ) 2 17

Creates a new error handling context and executes xt in that context.

If a throw (see below) is called during the execution of xt,

    1. The error handling context is removed
    2. The stack depth is restored to the depth that existed prior to the execution of xt (not counting the xt stack item)
    3. The error code that was passed to throw is pushed onto the stack
    4. catch returns

If throw is not called during the execution of xt, the error handling context is removed and catch returns a false. The stack effect is otherwise the same as if xt were executed using execute.

For example:

---------------------------------------------
: add-n-check-limit ( n1 n2 n3 -- n ) + + dup h# 30 if true throw then ; : add-me ( n1 n2 n3 -- a b c | n1+n2+n3 ) ['] add-n-check-limit catch if ." Sum exceeds limit " .s else ." Sum is within limit. Sum = " .s then cr ; ---------------------------------------------

Note that , given this definition:

---------------
1 2 3 add-me ---------------

shows :

------------------------------
Sum is within limit. Sum = 6 ------------------------------

while :

------------------
10 20 30 add-me ------------------

may show something like:

-----------------------------
Sum exceeds limit 50 9 12 -----------------------------

Note - On a non-zero throw, only the stack depth is guaranteed to be the same as before catch, not the data stack contents.

cell+
( addr1 -- addr2 ) 65

Increments addr1 by the value of /n. cell+ should be used in preference to wa1+ or la1+ when the intent is to address items that are the same size as items on the stack.

cells
( nu1 -- nu2 ) 69

nu2 is the result of multiplying nu1 by /n, the length in bytes of a normal stack item. This is useful for converting an index into a byte offset.

char-height
( -- height ) 1 6C

A value, containing the standard height (in pixels) for all characters to be drawn. This number, when multiplied by #lines, determines the total height (in pixels) of the active text area.

This word must be set to the appropriate value if you wish to use any fb1- or fb8- utility routines or >font. This can be done with to, but is normally done by calling set-font.

chars
( nu1 -- nu2 ) 66

nu2 is the result of multiplying nu1 by /c, the length in bytes of a byte. This is useful for converting an index into a byte offset.

char-width
( -- width ) 1 6D

A value, containing the standard width (in pixels) for all characters to be drawn. This number, when multiplied by #columns, determines the total width (in pixels) of the active text area.

This word must be set to an appropriate value if you want to use any fb1- or fb8- utility routines. This can be done with to, but is normally done by calling set-font.

child
( parent-phandle -- child-phandle ) 2 3B

Returns the phandle of the package that is the first child of the package parent-phandle.

child returns zero if the package parent-phandle has no children.

You will generally use child, together with peer, to enumerate (possibly recursively) the children of a particular device. One common use could be for bus adapter device drivers to use the phrase my-self ihandlephandle to develop the parent-phandle argument.

For example:

-----------------------------------------------------
: my-children ( -- ) \ shows phandles of all children my-self ihandlephandle child ( first-child ) begin ?dup while dup .h peer repeat ; -----------------------------------------------------
close-package
( ihandle -- ) 2 06

Closes the package instance identified by ihandle by calling that package's close method and then destroying the instance.

For example:

---------------------------------------------------
: tftp-load-avail? ( -- exist? ) 0 0 " obp-tftp" $open-package ( ihandle ) dup ihandlephandle " load" rot find-method if drop true else false then close-package ; ---------------------------------------------------
cmove'>
( adr1 adr2 len -- ) 78 generates: move

Copy len bytes of an array starting at adr1 to adr2. This word is an alias for move.

column#
( -- column# ) 1 53

A value, set and controlled by the terminal emulator, that contains the current horizontal position of the text cursor. A value of 0 represents the leftmost cursor position of the text window, not the leftmost pixel of the frame buffer.

column# can (and should) be looked at as needed if your FCode Program is implementing its own set of frame buffer primitives.

For example:

-----------------------------------------
: set-column ( column# -- ) 0 max #columns 1- min to column# ; -----------------------------------------

See also: window-left

#columns
( -- columns ) 1 51

This is a value that returns the number of columns of text in the text window i.e. the number of characters in a line, to be displayed using the boot PROM's terminal emulator.

#columns must be set to a proper value in order for the terminal emulator to function correctly. The open method of any package that uses the terminal emulator package must set #columns to the desired width of the text region. This can be done with to, or it can be handled automatically as one of the functions performed by fb1-install or fb8-install.

For example:

------------------------------------------
: set-column ( column# -- ) 0 max #columns 1- min to column# ; ------------------------------------------

See also: is-install, fb1-install, fb8-install

comp
( addr1 addr2 len -- n ) 7A

Compares two strings of length len starting at addresses addr1 and addr2 and continuing for len bytes. n is 0 if the arrays are the same. n is 1 if the first differing character in the array at addr1 is numerically greater than the corresponding character in the array at addr2. n is -1 if the first differing character in the array at addr1 is numerically less than the corresponding character in the array at addr2.

For example:

--------------------------------------
ok " this" drop " that" comp .h 1 ok " thisismy" drop " this" comp .h 0 ok " thin" drop " this" comp .h ffffffff --------------------------------------
compile,
( xt -- ) DD

Compiles the behavior of the word given by xt.

[compile]
( [old-name< ] -- ) none

Compiles the immediately-following command.

constant
( x "new-name< " -- ) (E: -- value ) (header) ba new-token|named-token|external-token b(constant)

Creates a named constant. The name is initially created with:

----------------------
123 constant purple ----------------------

where 123 is the desired value for purple.

Later occurrences of purple will leave the 123 on the stack. If you wish to change the value of a constant in a program, you should use value instead of constant.

control
( [text< ] -- char ) 10 00 00 00 xx b(lit) 00 00 00 xx-byte

Causes the compiler/interpreter to interpret the next letter as a control-code. For example:

--------------------------
control c ( equals 03 ) --------------------------
count
( pstr -- addr len ) 84

Converts a packed string into a byte-array format. pstr is the address of a packed string, where the byte at address pstr is the length of the string and the string itself starts at address pstr+1.

Packed strings are generally not used in FCode. Virtually all string operations are in the "addr len" format.

For example:

-------------------------------------------------------
h# 100 alloc-mem constant my-buff " This is a string" my-buff pack ( pstr ) count type -------------------------------------------------------
cpeek
( addr -- false | byte true ) 2 20

Tries to read the 8-bit byte at address addr. Returns the data and true if the access was successful. A false return indicates that a read access error occurred.

See also: rb@

cpoke
( byte addr -- okay? ) 2 23

Attempts to write the 8-bit byte at address addr. Returns true if the access was successful. A false return indicates that a write access error occurred.

Note - cpoke may be unreliable on bus adapters that buffer write accesses.

See also: rb!

cr
( -- ) 92

A defer word used to terminate the line on the display and go to the next line. The default implementation transmits a carriage return and line feed to the display, clears #out and adds 1 to #line.

Use cr whenever you want to start a new line of output, or to force the display of any previously buffered output text. This forcing is valuable for outputting error messages, to ensure that the error message is sent before any system crash.

For example:

----------------------------------------------
: show-info ( -- ) ." This is the first line of output " cr ." This is the second line of output " cr ; ----------------------------------------------
(cr
( -- ) 91

Outputs only the carriage return character (carret, 0x0D). The most common use of (cr is for reporting the progress of a test that has many steps. By using (cr instead of cr, the progress report appears on a single line instead of scrolling.

create
( "new-name< " -- ) (E: -- addr ) (header) bb new-token|named-token|external-token b(create)

Creates the name new-name. When new-name is subsequently executed, it returns the address of memory immediately following new-name in the dictionary. You can use create to build an array-type structure, as:

----------------------------------------------------
create green 77 c, 23 c, ff c, ff c, 47 c, 22 c, ... ----------------------------------------------------

Later execution of green leaves the address of the first byte of the array (here, the address of the byte "77") on the stack. The returned address will be two- byte aligned.

create may not be used in definitions in an FCode Program. The common Forth construct create...does is not supported.

d#
( [number< ] -- n ) 10 value b(lit) xx-byte xx-byte xx-byte xx-byte

Causes the compiler/interpreter to interpret the next number in decimal (base 10), regardless of any previous settings of hex, decimal or octal. Only the immediately following number is affected, the default numeric base setting is unchanged. For example:

--------------------------------
hex d# 100 ( equals decimal 100 ) 100 ( equals decimal 256 ) --------------------------------

See also: h#.

d+
( d1 d2 -- d.sum ) D8

Adds two double numbers, leaving the double sum on the stack.

For example:

----------------------------------------------
ok 1234.0000 0056.7800 9abc 3400.009a d+ .s 1234.9abc 3456.789a ----------------------------------------------
d-
( d1 d2 -- d.diff ) D9

Subtracts two double numbers, leaving the double result on the stack.

For example:

---------------------------------------------------
ok 0 6 1 0 d- .s ffff.ffff 5 ok 4444.8888 aaaa.bbbb 2222.1111 5555.2222 d- .s 2222.7777 5555.9999 ---------------------------------------------------
.d
( n -- ) A0 6D 49 10 00 00 00 0A A072 9D 9D A072 base @ swap d# 10 base ! . base !

Displays n in decimal with a trailing space. The value of base is not permanently affected.

decimal
( -- ) none generates: d# 10 base !

If used outside of a definition, commands the tokenizer program to interpret subsequent numbers in decimal (base 10).

If used in a definition, appends the phrase 10 base ! to the FCode Program that is being created thus affecting later numeric output when the FCode Program is executed.

See also: base

decode-bytes
( prop-addr1 prop-len1 data-len --
prop-addr2 prop-len2 data-addr data-len )
none >r over r@ + swap r@ - rot r'>

Decodes data-len bytes from a property value array and returns the remainder of the array and the decoded byte array.

decode-int
( prop-addr1 prop-len1 -- prop-addr2 prop-len2 n ) 2 1B

Decodes a number from the beginning of a property value array and returns the remainder of the property value array and the number n.

For example:

--------------------------------------------------------
: show-clock-frequency ( -- ) " clock-frequency" get-inherited-property 0= if ." Clock frequency: " decode-int .h cr 2drop then ; --------------------------------------------------------
decode-phys
( prop-addr1 prop-len1 -- prop-addr2 prop-len2 phys.lo ... phys.hi ) 1 28

Decodes a unit address from a property value array and returns the remainder of the array and the decoded list of address components. The number of cells in the list phys.lo ... phys.hi is determined by the value of the
#address-cells property of the parent node.

decode-string
( prop-addr1 prop-len1 -- prop-addr2 prop-len2 str len ) 2 1C

Decodes a string from the beginning of a property value array and returns the remainder of the property value array and the string str len.

For example:

----------------------------------------------------------------------
: show-model ( -- ) " model" get-my-property 0= if decode-string type 2drop then ; ----------------------------------------------------------------------
default-font
( -- fontaddr charwidth charheight #fontbytes #firstchar #chars ) 1 6A

Returns all the necessary information about the character font that is built into the boot PROM. This font defines the appearance of every character to be displayed. To load this font, simply pass these parameters to set-font, with:

-----------------------
default-font set-font -----------------------

The actual parameters returned by default-font are:

    fontaddr - The address of the beginning of the built-in font table

    charwidth - The width of each character in pixels

    charheight - The height of each character in pixels

    #fontbytes - The separation (in bytes) between each scan line entry

    #firstchar - The ASCII value for the first character actually stored in the font table.

    #chars - The total number of characters stored in the font table.

defer
( "new-name< " -- ) (E: -- ??? ) code: (header) bc new-token|named-token|external-token b(defer)

Creates a command new-name that is a defer word i.e. a word whose behavior can be altered with to. new-name is initially created with execution behavior that indicates that it is an uninitialized defer word. For example:

----------------------------------
ok defer blob ok blob <--deferred word not initialized ----------------------------------

Later, this behavior can then be altered to be that of another existing word by placing that second word's execution token on the stack and loading it into new-name with to. For example:

-----------------
['] foobar to blob -----------------

defer words are useful for generating recursive routines. For example:

----------------------------------
defer hold2 \ Will execute action2 : action1 ... hold2 ( really action2 ) ... ; : action2 ... action1 ... ; ' action2 to hold2 ----------------------------------

defer words can also be used for creating words with different behaviors depending on your needs. For example:

----------------------------------------------------------------
defer .special ( n -- ) \ Print a value, using special techniques : print-em-all ( -- ) ... .special ... .special ... .special ; ( .d prints in decimal ( .h prints in hexadecimal ) ( .sp prints in a custom format ) : print-all-styles ['] .d to .special print-em-all ['] .h to .special print-em-all ['] .sp to .special print-em-all ; ----------------------------------------------------------------

In FCode source, defer cannot appear inside a colon definition.

See also: behavior.

delete-characters
( n -- ) 1 5E

Deletes n characters to the right of the cursor.

delete-characters is one of the defer words of the display device interface. The terminal emulator package executes delete-characters when it has processed a character sequence that requires the deletion of characters to the right of the cursor. The cursor position is unchanged, the cursor character and the first n-1 characters to the right of the cursor are deleted. All remaining characters to the right of the cursor, including the highlighted character, are moved left by n places. The end of the line is filled with blanks.

This word is initially empty, but must be loaded with an appropriate routine in order for the terminal emulator to function correctly. This can be done with to, or it can be loaded automatically with fb1-install or fb8-install (which loads fb1-delete-characters or fb8-delete-characters, respectively).

See also: fb8-install.

delete-lines
( n -- ) 1 60

Deletes n lines at and below the cursor line.

delete-lines is one of the defer words of the display device interface. The terminal emulator package executes delete-lines when it has processed a character sequence that requires the deletion of lines of text below the line containing the cursor. All lines below the deleted lines are scrolled upwards by n lines, and n blank lines are placed at the bottom of the active text area.

Use this word for scrolling, by temporarily moving the cursor to the top of the screen and then calling delete-lines.

This word is initially empty, but must be loaded with an appropriate routine in order for the terminal emulator to function correctly. This can be done with to, or it can be loaded automatically with fb1-install or fb8-install (which loads fb1-delete-lines or fb8-delete-lines, respectively).

See also: fb8-install.

delete-property
( name-str name-len -- ) 2 1E

Deletes the property named by name-str name-len in the active package, if such a property exists.

For example:

--------------------------------------------
: unmap-me ( -- ) my-reg my-size " map-out" $call-parent " address" delete-property ; --------------------------------------------
depth
( -- u ) 51

u is the number of entries contained in the data stack, not counting itself. Note that when an FCode Program is called, there could be other items on the stack from the calling program.

depth is especially useful for before/after stack depth checking, to determine if the stack was corrupted by a particular operation.

device-name
( str len -- ) 2 01

Creates a name property with the given string value. For example:

--------------------------
" SUNW,ffb" device-name --------------------------

This is equivalent to using the name macro or

--------------------------------
encode-string " name" property --------------------------------

except that device-name performs the same function with only 2 bytes of FCode, instead of 10 bytes. This word could be useful for devices with extremely limited FCode space.

See also: name.

diagnostic-mode?
( -- diag? ) 1 20

FCode Programs can use diagnostic-mode? to control the extent of the selftests performed. If diagnostic-mode? is true, more extensive tests can be performed and more messages displayed.

For example:

-------------------------
diagnostic-mode? if do-extended-tests else do-normal-tests then -------------------------

FCode should not generate character output during probing unless diagnostic-mode? is true, or unless an error is encountered. Error output during probing typically goes to the system serial port.

diagnostic-mode? will return true if any of the following conditions are met:

digit
( char base -- digit true | char false ) A3

If the character char is a digit in the specified base, returns the numeric value of that digit under true, else returns the character under false. Appropriate characters are hex 30-39 (for digits 0-9) and hex 61-66 (for digits a-f), depending on base.

For example:

------------------------------------------------------------
: probe-slot ( slot# -- ) ... ; : probe-slots ( addr cnt -- ) bounds ?do i c@ d# 16 digit if probe-slot else drop then loop ; ------------------------------------------------------------
do
( C: -- dodest-sys ) ( limit start -- ) ( R: -- sys ) 17 +offset b(do) +offset

Begins a counted loop in the form do...loop or do...+loop. The loop index begins at start, and terminates based on limit. See loop and +loop for details on how the loop is terminated. The loop is always executed at least once. For example:

-------------------------------------------
8 3 do i . loop \ would print 3 4 5 6 7 9 3 do i . 2 +loop \ would print 3 5 7 -------------------------------------------

do may be used either inside or outside of colon definitions.

?do
( C: -- dodest-sys ) ( limit start -- ) ( R: -- sys ) 18 +offset b(?do) +offset

Begin a counted loop in the form ?do...loop or ?do...+loop. The loop index begins at start, and terminates based on limit. See loop and +loop for details on how the loop is terminated. Unlike do, if start is equal to limit the loop is executed zero times. For example:

-----------------------------------------------------
8 1 ?do i . loop \ would print 1 2 3 4 5 6 7 2 1 ?do i . loop \ would print 1 1 1 ?do i . loop \ would print nothing 1 1 do i . loop \ would print 1 2 3 4 5 6 7 8 9 ... ... -----------------------------------------------------

?do can be used in place of do in nearly all circumstances. ?do may be used either inside or outside of colon definitions.

draw-character
( char -- ) 1 57

A defer word that is called by the terminal emulator in order to display a single character on the screen at the current cursor location.

This word is initially empty, but must be loaded with an appropriate routine in order for the terminal emulator to function correctly. This can be done with to, or it can be loaded automatically with fb1-install or fb8-install (which loads fb1-draw-character or fb8-draw-character, respectively).

draw-logo
( line# addr width height -- ) 1 61

A defer word that is called by the system to display the power-on logo (the graphic displayed on the left side during power-up, or by banner).

This word is initially empty, but must be loaded with an appropriate routine in order for the terminal emulator to function correctly. This can be done with to, or it can be loaded automatically with fb1-install or fb8-install (which loads fb1-draw-logo or fb8-draw-logo, respectively).

It is possible to pack a custom logo into the FCode PROM and then re-initialize draw-logo to output the custom logo instead.

draw-logo is called by the system using the following parameters:

    line# - The text line number at which to draw the logo.

    addr - The address of the logo template to be drawn. In practice, this will always be either the address of the oem-logo field in NVRAM, the address of a custom logo in the FCode PROM, or the address of the built-in system logo. In any case, the logo is an array of 64x64 (hex) pixels.

    width - The width of the passed-in logo (in pixels).

    height- The height of the passed-in logo (in pixels).

drop
( x -- ) 46

Removes one item from the stack.

2drop
( x1 x2 -- ) 52

Removes two items from the stack.

3drop
( x1 x2 x3 -- ) none drop 2drop

Removes three items from the stack.

dup
( x -- x x ) 47

Duplicates the top stack item.

2dup
( x1 x2 -- x1 x2 x1 x2 ) 53

Duplicates the top two stack items.

3dup
( x1 x2 x3 -- x1 x2 x3 x1 x2 x3 ) a7 he a7 4e a7 4e 2 pick 2 pick 2 pick

Duplicates the top three stack items.

?dup
( x -- 0 | x x ) 50

Duplicates the top stack item unless it is zero.

else
( C: orig-sys1 -- orig-sys2 ) ( -- ) 13 +offset b2 bbranch +offset b(resolve)

Begin the else clause of an if...else...then statement. See if for more details.

emit
( char -- ) 8f

A defer word that outputs the indicated ASCII character. For example, h# 41 emit outputs an "A", h# 62 emit outputs a "b", h# 34 emit outputs a "4".

emit-byte
( FCode# -- ) n n

An FCode-only command used to manually output a desired byte of FCode. Use it together with tokenizer[ as follows:

-----------------------------
tokenizer[ 44 emit-byte 20 emit-byte ]tokenizer -----------------------------

emit-byte would be useful, for example, if you wished to generate a new FCode command that the tokenizer did not understand. This command should be used with caution or else an invalid FCode Program will result.

See also: tokenizer[

encode+
( prop-addr1 prop-len1 prop-addr2 prop-len2 -- prop-addr3 prop-len3 ) 01 12

Merge two property value arrays into a single property value array. The two input arrays must have been created sequentially with no intervening dictionary allocation or other property value arrays having been created. This can be called repeatedly, to create complex, multi-valued property value arrays for passing to property.

For example, suppose you wished to create a property named myprop with the following information packed sequentially:

--------------------------------
"size" 2000 "vals" 3 128 40 22 --------------------------------

This could be written in FCode as follows:

--------------------------------------------
: encode-string,num ( addr len number -- ) r encode-string r encode-int encode+ ; " size" 2000 encode-string,num " vals" 3 encode-string,num encode+ 128 encode-int encode+ 40 encode-int encode+ 22 encode-int encode+ " myprop" property --------------------------------------------
encode-bytes
( data-addr data-len -- prop-addr prop-len ) 1 15

Encodes a byte array into a property value array. The external representation of a byte array is the sequence of bytes itself, with no appended null byte.

For example:

-------------------------------------------------
my-idprom h# 20 encode-bytes " idprom" property -------------------------------------------------
encode-int
( n -- prop-addr prop-len ) 01 11

Convert an integer into a property value array, suitable for passing as a value to property. For example:

-----------------------------------
1152 encode-int " hres" property -----------------------------------
encode-phys
( phys.lo ... phys.hi -- prop-addr prop-len ) 01 13

Encodes a unit-address into a property value array by property encoding the list of cells denoting a unit address in the order of phys.hi followed by the encoding of the component that appears on the stack below phys.hi, and so on, ending with the encoding of the phys.lo component.

The number of cells in the list phys.lo ... phys.hi is determined by the value of the "#address-cells" property of the parent node.

For example:

------------------------------------------------------
my-address my-space encode-phys " resetloc" property ------------------------------------------------------
encode-string
( str len -- prop-addr prop-len ) 01 14

Converts an ordinary string, such as created by ", into a property value array suitable for property. For example:

---------------------------------------------------
" NSL,DTE,AUU" encode-string " authors" property ---------------------------------------------------
end0
( -- ) 00

A word that marks the end of an FCode Program. This word must be present at the end of your program or erroneous results may occur.

If you want to use end0 inside a colon definition, for example in a conditional clause, use something like:

----------------------------------------------------------------------------
: exit-if-version1 fcode-revision h# 20000 < if ['] end0 execute then ; ----------------------------------------------------------------------------
end1
( -- ) FF

An alternate word for end0, to mark the end of an FCode Program. end0 is recommended.

end1 is not intended to appear in source code. It is defined as a guard against mis-programmed ROMs. Unprogrammed regions of PROM usually appear as all ones or all zeroes.Having both 0x00 and 0xFF defined as end codes stops the FCode interpreter if it enters an unprogrammed region of a PROM.

endcase
( C: case-sys -- ) ( sel | <nothing -- ) C5 generates: b(endcase)

Marks the end of a case statement. See case for more details.

endof
( C: case-sys1 of-sys -- case-sys2 ) ( -- ) C6 +offset b(endof) +offset

Marks the end of an of clause in a case statement. See case for more details.

erase
( addr len -- ) 95 79 0 fill

Sets len bytes of memory beginning at addr to zero. No action is taken if len is zero.

erase-screen
( -- ) 1 5A

A defer word that is called once during the terminal emulator initialization sequence in order to completely clear all pixels on the display. This word is called just before reset-screen, so that the user doesn't actually see the frame buffer data until it has been properly scrubbed.

This word is initially empty, but must be loaded with an appropriate routine in order for the terminal emulator to function correctly. This can be done with to, or it can be loaded automatically with fb1-install or fb8-install (which loads fb1-erase-screen or fb8-erase-screen, respectively).

eval
( ??? str len -- ??? ) CD generates: evaluate

Synonym for evaluate.

evaluate
( ??? str len -- ??? ) CD

Executes a string as a sequence of Forth commands. The overall stack effect depends on the commands being executed. For example:

---------------------------
" 4000 20 dump" evaluate ---------------------------

You can use evaluate, like $find, to find and execute Forth commands that are not FCodes.

The same cautions apply to evaluate as for $find in that programs executing Forth commands are likely to encounter portability problems when moved to other systems.

execute
( ??? xt -- ??? ) 1D

Executes the word definition whose execution token is xt. An error condition exists if xt is not an execution token.

For example:

-----------------------------------
: my-word ( addr len -- ) ." Given string is: " type cr ; " great" ['] my-word execute -----------------------------------
exit
( -- ) ( R: sys -- ) 33

Compiled in a colon definition. When encountered, execution leaves the current word and returns control to the calling word. If used in a do loop must be preceded by unloop.

For example:

----------------------------------------------------------
: probe-loop ( addr -- ) \ generate a tight probe loop until any key is pressed. begin dup l@ drop key? if drop exit then again ; ----------------------------------------------------------

See also: leave, unloop

expect
( addr len -- ) 8A

A defer word that receives a line of characters from the keyboard and stores them into memory, performing line editing as the characters are typed. Displays all characters actually received and stored into memory. The number of received characters is stored in span.

The transfer begins at addr proceeding towards higher addresses one byte per character until either a carriage return is received or until len characters have been transferred. No more than len characters will be stored. The carriage return is not stored into memory. No characters are received or transferred if len is zero.

For example:

------------------------------------------------------------------
h# 10 buffer: my-name-buff : hello ( -- ) ." Enter Your First name " my-name-buff h# 10 expect ." Sun Microsystems Welcomes " my-name-buff span @ type cr ; ------------------------------------------------------------------
external
( -- ) none

After issuing external, all subsequent definitions are created so that names are later compiled into RAM, regardless of the value of the NVRAM variable fcode-debug?. external is used to define the package methods that may be called from other software external to the package, and whose names must therefore be present.

external stays in effect until headers or headerless is encountered.

For example:

-----------------------
external : open ( -- ok? ) ... ; -----------------------
external-token
( -- ) CA

A token-type that is used to indicate that this word should always be compiled with the name header present. Activated by external, all subsequent words are created with external-token until deactivated with either headers or headerless. See named-token for more details. This word should never be used in source code.

false
( -- false ) a5 0

Leaves the value for false (i.e. zero) on the stack.

fb1-blink-screen
( -- ) 01 74

The built-in default routine to blink or flash the screen momentarily on a generic 1-bit-per-pixel frame buffer. This routine is loaded into the defer word blink-screen by calling fb1-install.

This routine is invalid unless the FCode Program has called fb1-install and has initialized frame-buffer-adr to a valid virtual address.

This word is implemented simply by calling fb1-invert-screen twice. In practice, this can be quite slow (around one full second). It is quite common for a frame buffer FCode Program to replace fb1-blink-screen with a custom routine that simply disables the video for 20 milliseconds or so. For example:

----------------------------------------------------------
: my-blink-screen ( -- ) video-off 20 ms video-on ; ... fb1-install ... ['] my-blink-screen to blink-screen ----------------------------------------------------------
fb1-delete-characters
( n -- ) 01 77

The built-in default routine to delete n characters at and to the right of the cursor, on a generic 1-bit-per-pixel frame buffer. This routine is loaded into the defer word delete-characters by calling fb1-install.

This routine is invalid unless the FCode Program has called fb1-install and set-font and has initialized frame-buffer-adr to a valid virtual address.

The cursor position is unchanged, the cursor character and the next n-1 characters to the right of the cursor are deleted, and the remaining characters to the right are moved left by n places. The end of the line is filled with blanks.

fb1-delete-lines
( n -- ) 01 79

The built-in default routine to delete n lines, starting with the line below the cursor line, on a generic 1-bit-per-pixel frame buffer. This routine is loaded into the defer word delete-lines by calling fb1-install.

This routine is invalid unless the FCode Program has called fb1-install and set-font and has initialized frame-buffer-adr to a valid virtual address.

The n lines at and below the cursor line are deleted. All lines above the cursor line are unchanged. The cursor position is unchanged. All lines below the deleted lines are scrolled upwards by n lines, and n blank lines are placed at the bottom of the active text area.

fb1-draw-character
( char -- ) 01 70

The built-in default routine for drawing a character on a generic 1-bit-per-pixel frame buffer, at the current cursor location. This routine is loaded into the defer word draw-character by calling fb1-install.

This routine is invalid unless the FCode Program has called fb1-install and set-font and has initialized frame-buffer-adr to a valid virtual address.

If inverse? is true, then characters are drawn inverted (white-on-black). Otherwise (the normal case) they are drawn black-on-white.

fb1-draw-logo
( line# logoaddr logowidth logoheight -- ) 01 7A

The built-in default routine to draw the logo on a generic 1-bit-per-pixel frame buffer. This routine is loaded into the defer word draw-logo by calling fb1-install.

This routine is invalid unless the FCode Program has called fb1-install and set-font and has initialized frame-buffer-adr to a valid virtual address.

See draw-logo for more information on the parameters passed.

fb1-erase-screen
( -- ) 01 73

The built-in default routine to clear (erase) every pixel in a generic 1-bit-per- pixel frame buffer. This routine is loaded into the defer word erase-screen by calling fb1-install.

This routine is invalid unless the FCode Program has called fb1-install and has initialized frame-buffer-adr to a valid virtual address.

All pixels are erased (not just the ones in the active text area). If inverse- screen? is true, then all pixels are set to 1, resulting in a black screen. Otherwise (the normal case) all pixels are set to 0, resulting in a white screen.

fb1-insert-characters
( n -- ) 01 76

The built-in default routine to insert n blank characters to the right of the cursor, on a generic 1-bit-per-pixel frame buffer. This routine is loaded into the defer word insert-characters by calling fb1-install.

This routine is invalid unless the FCode Program has called fb1-install and set-font and has initialized frame-buffer-adr to a valid virtual address.

The cursor position is unchanged, but the cursor character and all characters to the right of the cursor are moved right by n places. An error condition exists if an attempt is made to create a line longer than the maximum line size (the value in #columns).

fb1-insert-lines
( n -- ) 01 78

The built-in default routine to insert n blank lines below the cursor on a generic 1-bit-per-pixel frame buffer. This routine is loaded into the defer word insert-lines by calling fb1-install.

This routine is invalid unless the FCode Program has called fb1-install and set-font and has initialized frame-buffer-adr to a valid virtual address.

The cursor position on the screen is unchanged. The cursor line is pushed down, but all lines above it are unchanged. Any lines pushed off of the bottom of the active text area are lost.

fb1-install
( width height #columns #lines -- ) 01 7B

This built-in routine installs all of the built-in default routines for driving a generic 1-bit-per-pixel frame buffer. It also initializes most necessary values needed for using these default routines.

set-font must be called, and frame-buffer-adr initialized, before fb1-install is called, because the char-width and char-height values set by set-font are needed when fb1-install is executed.

fb1-install loads the following defer routines with their corresponding fb1-(whatever) equivalents: reset-screen, toggle-cursor, erase- screen, blink-screen, invert-screen, insert-characters, delete- characters, insert-lines, delete-lines, draw-character, draw- logo.

The following values are initialized:

    screen-width - set to the value of the passed-in parameter width (screen width in pixels)

    screen-height - set to the value of the passed-in parameter height (screen height in pixels)

    #columns - set to the smaller of the following two: the passed-in parameter #columns, and the NVRAM parameter screen-#columns

    #lines - set to the smaller of the following two: the passed-in parameter #lines, and the NVRAM parameter screen-#rows

    window-top - set to half of the difference between the total screen height (screen-height) and the height of the active text area (#lines times char-height)

    window-left - set to half of the difference between the total screen width (screen-width) and the width of the active text area (#columns times charwidth), then rounded down to the nearest multiple of 32 (for performance reasons)

Several internal values used by various fb1- routine are also set.

fb1-invert-screen
( -- ) 01 75

The built-in default routine to invert every visible pixel on a generic 1-bit-per- pixel frame buffer. This routine is loaded into the defer word invert- screen by calling fb1-install.

This routine is invalid unless the FCode Program has called fb1-install and has initialized frame-buffer-adr to a valid virtual address.

All pixels are inverted (not just the ones in the active text area).

fb1-reset-screen
( -- ) 01 71

The built-in default routine to enable a generic 1-bit-per-pixel frame buffer to display data. This routine is loaded into the defer word reset-screen by calling fb1-install. (reset-screen is called just after erase-screen during the terminal emulator initialization sequence.)

This word is initially a NOP. Typically, an FCode Program will define a hardware-dependent routine to enable video, and then replace this generic function with:

-----------------------------------
: my-video-enable ( -- ) ... : fb1-install ... ['] my-video-enable to reset-screen -----------------------------------
fb1-slide-up
( n -- ) 01 7C

This is a utility routine. It behaves exactly like fb1-delete-lines, except that it doesn't clear the lines at the bottom of the active text area. Its only purpose is to scroll the enable plane for frame buffers that have 1-bit overlay and enable planes.

This routine is invalid unless the FCode Program has called fb1-install and set-font and has initialized frame-buffer-adr to a valid virtual address.

fb1-toggle-cursor
( -- ) 01 72

The built-in default routine to toggle the cursor location in a generic 1-bit-per- pixel frame buffer. This routine is loaded into the defer word toggle- cursor by calling fb1-install. The behavior is to invert every pixel in the one-character-size space for the current position of the text cursor.

This routine is invalid unless the FCode Program has called fb1-install and set-font and has initialized frame-buffer-adr to a valid virtual address.

fb8-blink-screen
( -- ) 01 84

The built-in default routine to blink or flash the screen momentarily on a generic 8-bit-per-pixel frame buffer. This routine is loaded into the defer word blink-screen by calling fb8-install.

This routine is invalid unless the FCode Program has called fb8-install and has initialized frame-buffer-adr to a valid virtual address.

This word is implemented simply by calling fb8-invert-screen twice. In practice, this can be very slow (several seconds). It is quite common for a frame buffer FCode Program to replace fb8-blink-screen with a custom routine that simply disables the video for 20 milliseconds or so. For example:

------------------------------------------------------------
: my-blink-screen ( -- ) video-off 20 ms video-on ; ... fb8-install ... ['] my-blink-screen to blink-screen ------------------------------------------------------------
fb8-delete-
characters
( n -- ) 01 87

The built-in default routine to delete n characters to the right of the cursor, on a generic 8-bit-per-pixel frame buffer. This routine is loaded into the defer word delete-characters by calling fb8-install.

This routine is invalid unless the FCode Program has called fb8-install and set-font and has initialized frame-buffer-adr to a valid virtual address.

The cursor position is unchanged. The cursor character and the next n-1 characters to the right of the cursor are deleted, and the remaining characters to the right are moved left by n places. The end of the line is filled with blanks.

fb8-delete-lines
( n -- ) 01 89

The built-in default routine to delete n lines, starting with the line below the cursor line, on a generic 8-bit-per-pixel frame buffer. This routine is loaded into the defer word delete-lines by calling fb8-install.

This routine is invalid unless the FCode Program has called fb8-install and set-font and has initialized frame-buffer-adr to a valid virtual address.

The n lines at and below the cursor line are deleted. All lines above the cursor line are unchanged. The cursor position is unchanged. All lines below the deleted lines are scrolled upwards by n lines, and n blank lines are placed at the bottom of the active text area.

fb8-draw-character
( char -- ) 01 80

The built-in default routine for drawing a character on a generic 8-bit-per-pixel frame buffer, at the current cursor location. This routine is loaded into the defer word draw-character by calling fb8-install.

This routine is invalid unless the FCode Program has called fb8-install and set-font and has initialized frame-buffer-adr to a valid virtual address.

If inverse? is true, then characters are drawn inverted (white-on-black). Otherwise (the normal case) they are drawn black-on-white.

fb8-draw-logo
( line# addr width height -- ) 01 8A

The built-in default routine to draw the logo on a generic 8-bit-per-pixel frame buffer. This routine is loaded into the defer word draw-logo by calling fb8-install.

This routine is invalid unless the FCode Program has called fb8-install and set-font and has initialized frame-buffer-adr to a valid virtual address.

See draw-logo for more information on the parameters passed.

fb8-erase-screen
( -- ) 01 83

The built-in default routine to clear (erase) every pixel in a generic 8-bit-per- pixel frame buffer. This routine is loaded into the defer word erase-screen by calling fb8-install.

This routine is invalid unless the FCode Program has called fb8-install and has initialized frame-buffer-adr to a valid virtual address.

All pixels are erased (not just the ones in the active text area). If inverse- screen? is true, then all pixels are set to 0xff, resulting in a black screen. Otherwise (the normal case) all pixels are set to 0, resulting in a white screen.

fb8-insert-
characters
( n -- ) 01 86

The built-in default routine to insert n blank characters to the right of the cursor, on a generic 8-bit-per-pixel frame buffer. This routine is loaded into the defer word insert-characters by calling fb8-install.

This routine is invalid unless the FCode Program has called fb8-install and set-font and has initialized frame-buffer-adr to a valid virtual address.

The cursor position is unchanged, but the cursor character and all characters to the right of the cursor are moved right by n places. An error condition exists if an attempt is made to create a line longer than the maximum line size (the value in #columns).

fb8-insert-lines
( n -- ) 01 88

The built-in default routine to insert n blank lines below the cursor on a generic 8-bit-per-pixel frame buffer. This routine is loaded into the defer word insert-lines by calling fb8-install.

This routine is invalid unless the FCode Program has called fb8-install and set-font and has initialized frame-buffer-adr to a valid virtual address.

The cursor position is unchanged. The cursor line is pushed down, but all lines above it are unchanged. Any lines pushed off of the bottom of the active text area are lost.

fb8-install
( width height #columns #lines -- ) 01 8B

This built-in routine installs all of the built-in default routines for driving a generic 8-bit-per-pixel frame buffer. It also initializes most necessary values needed for using these default routines.

set-font must be called, and frame-buffer-adr initialized, before fb8-install is called, because the char-width and char-height values set by set-font are needed when fb8-install is executed.

fb8-install loads the following defer routines with their corresponding fb8-(whatever) equivalents: reset-screen, toggle-cursor, erase- screen, blink-screen, invert-screen, insert-characters, delete- characters, insert-lines, delete-lines, draw-character, draw- logo

The following values are initialized:

    screen-width - set to the value of the passed-in parameter width (screen width in pixels)

    screen-height - set to the value of the passed-in parameter height (screen height in pixels)

    #columns - set to the smaller of the following two: the passed-in parameter #columns, and the NVRAM parameter screen-#columns

    #lines - set to the smaller of the following two: the passed-in parameter #lines, and the NVRAM parameter screen-#rows

    window-top - set to half of the difference between the total screen height (screen-height) and the height of the active text area (#lines times char-height)

    window-left - set to half of the difference between the total screen width (screen-width) and the width of the active text area (#columns times char-width), then rounded down to the nearest multiple of 32 (for performance reasons)

Several internal values are also set that are used by various fb8- routines.

fb8-invert-screen
( -- ) 01 85

The built-in default routine to XOR (with hex 0xFF) every visible pixel on a generic 8-bit-per-pixel frame buffer. This routine is loaded into the defer word invert-screen by calling fb8-install.

This routine is invalid unless the FCode Program has called fb8-install and has initialized frame-buffer-adr to a valid virtual address.

All pixels are inverted (not just those in the active text area).

fb8-reset-screen
( -- ) 01 81

The built-in default routine to enable a generic 8-bit-per-pixel frame buffer to display data. This routine is loaded into the defer word reset-screen by calling fb8-install. (reset-screen is called just after erase-screen during the terminal emulator initialization sequence.)

This word is initially a NOP. Typically, an FCode Program will define a hardware-dependent routine to enable video, and then replace this generic function with:

-----------------------------------
: my-video-enable ( -- ) ... : fb8-install ... ['] my-video-enable to reset-screen -----------------------------------
fb8-toggle-cursor
( -- ) 01 82

The built-in default routine to toggle the cursor location in a generic 8-bit-per- pixel frame buffer. This routine is loaded into the defer word toggle- cursor by calling fb8-install. The behavior is to XOR every pixel with 0xFF in the one-character-size space for the current position of the text cursor.

This routine is invalid unless the FCode Program has called fb8-install and set-font and has initialized frame-buffer-adr to a valid virtual address.

fcode-revision
( -- n ) 87

Returns a 32-bit number identifying the version of the device interface. The high 16 bits is the major version number and the low 16 bits is the minor version number. The revision of the device interface described by IEEE Standard 1275-1994 is "3.0". In a system compatible with that specification, fcode-revision will return 0x0003.0000.

For example:

-------------------------------------------------------
: exit-if-not-1275-1994 ( -- ) fcode-revision h# 30000 < if ['] end0 execute then ; -------------------------------------------------------
fcode-version1
( -- ) fd hh xx yy aa bb cc dd

This tokenizer macro is used to start FCode programs intended to be compatible with early OpenBoot systems.

fcode-version1 generates the FCode header for an FCode program (based on tokenizer switches). If the default tokenizer switches are used, fcode- version1 begins the header with the version1 FCode.

fcode-version2
( -- ) f1 hh xx yy aa bb cc dd

Starts a version2 FCode program, generating an 8-byte header similar to fcode-version1, except that the starting byte is start1 (f1) instead of version1 (fd).

For example:

--------------------------------------------
fcode-version2 " SUNW,nvsimm" xdrstring " name" attribute ... end0 --------------------------------------------

Caution - FCode programs created with fcode-version2 will only run on OpenBoot 2 or later systems. They will not work on OpenBoot 1.0 systems.

ferror
( -- ) FC

Displays an "Unimplemented FCode" error message and stops FCode interpretation at the completion of the function whose evaluation resulted in the execution of ferror. All unimplemented FCode numbers resolve to ferror in OpenBoot.

The intended use of ferror is to determine whether or not a particular FCode is implemented, without checking the FCode version number.

For example:

------------------------------------------
: implemented? ( xt -- flag) ['] ferror < ; : my-peer ( prev -- next ) ['] peer implemented? if peer else ." peer is not implemented" cr then ; ------------------------------------------
field
( E: addr -- addr+offset ) ( offset size "new-name<" -- offset+size ) (header) be new-token|named-token|external-token b(field)

struct and field are used to create named offset pointers into a structure. For each field in the structure, a name is assigned to the location of that field (as an offset from the beginning of the structure).

The structure being described is:

----------------------------
\ size Bytes 0 - 1 \ flags Bytes 2 - 5 \ bits Byte 6 \ key Byte 7 \ fullname Bytes 8 - 17 \ initials Bytes 8 - 9 \ lastname Bytes 10 - 17 \ age Bytes 18 - 19 ----------------------------

The field definitions are shown below. (The numbers in parentheses show the stack after each word is created.)

---------------------------------------------------------------
struct ( 0 ) 2 field size ( 2 ) \ equivalent to: : size 0 + ; 4 field flags ( 6 ) \ equivalent to: : flags 2 + ; 1 field bits ( 7 ) \ equivalent to: : bits 6 + ; 1 field key ( 8 ) \ equivalent to: : key 7 + ; 0 field fullname ( 8 ) \ equivalent to: : fullname 8 + ; 2 field initials ( 10 ) \ equivalent to: : initials 8 + ; 8 field lastname ( 18 ) \ equivalent to: : lastname 10 + ; 2 field age ( 20 ) \ equivalent to: : age 18 + ; constant /record ( ) \ equivalent to: 20 constant /record ---------------------------------------------------------------

Typical usage of these defined words would be:

--------------------------------------------------------
/record buffer: myrecord \ Create the "myrecord" buffer myrecord flags l@ \ get flags data myrecord key c@ \ get key data myrecord size w@ \ get size data /record \ get total size of the array --------------------------------------------------------

Note that struct is primarily a documentation aid that the initial value of the structure's size (i.e. 0) on the stack.

fill
( addr len byte -- ) 79

Sets len bytes of memory beginning at addr to the value byte. No action is taken if len = 0.

$find
( name-str name-len -- xt true | name-str name-len false ) CB

Takes a string from the stack and searches the current search order for it. During normal FCode evaluation, the search order consists of the vocabulary containing the visible methods of the current device node, followed by the Forth vocabulary.

If the word is not found, the original string is left on the stack, with a false on top of the stack. If the word is found, the execution token of that word is left on the stack with true on top of the stack.

$find is an escape hatch, allowing an FCode Program to perform any function that is available in the OpenBoot User Interface but that is not defined as part of the standard FCode interface.

Use $find with caution! Different systems or even different versions of OpenBoot may implement different subsets of the User Interface. If your FCode Program depends on a User Interface word, it might not work on some systems.

Example of use:

----------------------------------------------------
" root-info" $find ( addr len false | xt true ) if execute \ if found, then do the function else ( addr len ) type ." was not found!" cr then ----------------------------------------------------
find-method
( method-str method-len phandle -- false | xt true ) 2 07

Locates the method named by method-str method-len in the package phandle. Returns false if the package has no such method, or xt and true if the operation succeeds. Subsequently, xt can be used with call-package.

For example:

----------------------------------------------
: tftp-load-avail? ( -- exist? ) " obp-tftp" find-package if ( phandle ) " load" rot find-method if ( xt ) drop true exit then then false ; ----------------------------------------------
find-package
( name-str name-len -- false | phandle true ) 2 04

Locates a package whose name is given by the string name-str name-len. If the package can be located, returns its phandle and true. Otherwise returns false.

The name is interpreted relative to the /packages device node. For example, if name-str name-len represents the string "disk-label", the package in the device tree at "/packages/disk-label" will be located.

If there are multiple packages with the same name (in the /packages node), the phandle for the most recently created one is returned.

For example:

----------------------------------------------
: tftp-load-avail? ( -- exist? ) " obp-tftp" find-package if ( phandle ) " load" rot find-method if ( xt ) drop true exit then then false ; ----------------------------------------------
finish-device
( -- ) 01 27

The two words finish-device and new-device let a single FCode Program declare more than one entry into the device tree. This capability is useful when a single SBus card contains two or more essentially independent devices, to be controlled by two or more separate operating system device drivers.

Typical usage:

----------------------------------------------
version1 ...driver#1... finish-device \ terminate device tree entry#1 new-device \ begin a new device tree entry ...driver#2 finish-device \ terminate device tree entry#2 new-device \ begin a new device tree entry ...driver#3... end0 ----------------------------------------------

There is an implicit new-device call at the beginning of an FCode Program (at version1 or start1), and an implicit finish-device call at the end of an FCode Program (at end0). Thus, FCode Programs that only define a single device and driver will never need to call finish-device or new-device.

fload
( [filename<cr] -- ) none

This command allows FCode text programs to be broken into function blocks for better clarity, portability and re-use. It behaves similarly to the #include statement in the C language. Arbitrary nesting of files with fload is allowed i.e. an fload'd file may include fload commands.

When fload is encountered, the Tokenizer continues tokenizing the FCode found in the file filename. When the filename has been tokenized, tokenizing resumes on the file that called filename with fload.

For example:

----------------------------
fload my-disk-package.fth ----------------------------

Note - fload commands won't work when downloading text in source-code form. You can either manually merge the files into one larger text file and use dl for downloading, or you can tokenize the files first and then download and execute the FCode in binary form.

>font
( char -- addr ) 01 6E

This routine converts a character value (ASCII 0-0xFF) into the address of the font table entry for that character. For the normal, built-in font, only ASCII values 0x21-0x7E result in a printable character, other values will be mapped to a font entry for "blank".

This word is only of interest if you are implementing your own character- drawing routines. Note that >font will generate invalid results unless set- font has been called to initialize the font table to be used.

fontbytes
( -- bytes ) 01 6F

A value, containing the interval between successive entries in the font table. Each entry contains the next scan line bits for the desired character. Each scan line is normally 12 pixels wide, and is stored as one bit per pixel, thus taking 1 1/2 bytes per scan line. The standard value for fontbytes is 2, meaning that the next scan line entry is 2 bytes after the previous one (the last 1/2 byte is wasted space).

This word must be set to the appropriate value if you wish to use any fb1- or fb8- utility routines or >font. This can be done with to, but is normally done by calling set-font.

The standard value for fontbytes is one of the parameters returned by default-font.

frame-buffer-adr
( -- addr ) 01 62

This value returns the virtual address of the beginning of the current frame buffer memory. It must be set to an appropriate virtual address (using to) in order to use any of the fb1- or fb8- utility routines. It is suggested that this same value variable be used in any of your custom routines that require a frame buffer address, although of course you are free to create and use your own variable if you wish.

Generally, you should only map in the frame buffer memory just before you are ready to use it, and unmap it if it is no longer needed. Typically, this means you should do your mapping in your "install" routine, and unmap it in your "remove" routine (see is-install and is-remove). Here's some sample code:

-------------------------------------------------------------------
h# 2.0000 constant /frame \ # of bytes in frame buffer h# 40.0000 constant foffset \ Location of frame buffer : video-map ( -- ) my-address foffset + /frame map-low to frame-buffer-adr ; : video-unmap ( -- ) frame-buffer-adr /frame free-virtual -1 to frame-buffer-adr \ Flag accidental accesses to a \ now-illegal address ; : power-on-selftest ( -- ) video-map ( test video memory ) video-unmap ; power-on-selftest : my-install ( -- ) video-map ... ; : my-remove ( -- ) video-unmap ... ; ... ['] my-install is-install ['] my-remove is-remove -------------------------------------------------------------------
free-mem
( a-addr len -- ) 8C

Frees up len memory allocated by alloc-mem. The arguments a-addr and len must be the same as those used in a previous alloc-mem command.

For example:

-----------------------------------------------------------------
0 value my-string \ Holds address of temporary : .upc-string ( addr len -- ) \ convert to uppercase and print. dup alloc-mem to my-string ( addr len ) tuck my-string swap move ( len ) my-string over bounds ?do i c@ upc i c! loop ( len ) my-string over type ( len ) my-string swap free-mem ; -----------------------------------------------------------------
free-virtual
( virt size -- ) 01 05

Destroys an existing mapping and any "address" property.

If the package associated with the current instance has an "address" property whose first value encodes the same address as virt, delete that property. In any case, execute the parent instance's map-out method with virt size as its arguments.

get-inherited-
property
( name-str name-len -- true | prop-addr prop-len false ) 2 1d

Locates, in the package associated with the current instance or any of its parents, the property whose name is name-addr name-len. If the property exists, returns the property value array prop-addr prop-len and false. Otherwise returns true.

The order in which packages are searched is the current instance first, followed by its immediate parent, followed by its parent's parent, and so on. This is useful for properties with default values established by a parent node, with the possibility of a particular child node "overriding" the default value.

For example:

------------------------------------------------------
: clock-frequency ( -- val.addr len false | true ) " clock-frequency" get-inherited-property ; ------------------------------------------------------
get-msecs
( -- n ) 01 25

Returns the current value in a free-running system counter. The number returned is a running total, expressed in milliseconds. You can use this for measuring time intervals (by comparing the starting value with the ending value). No assumptions should be made regarding the absolute number returned; only relative interval comparisons are valid.

No assumptions should be made regarding the precision of the number returned. In some systems, the value is derived from the system clock, which typically ticks once per second. Thus, the value returned by get-msecs on such a system will be seen to increase in jumps of 1000 (decimal), once per second.

For a delay timer of millisecond accuracy, see ms.

get-my-property
( name-str name-len -- true | prop-addr prop-len false ) 02 1A

Locates, in the package associated with the current instance, the property named by name-addr name-len. If the property exists, returns the property value array val-addr val-len and false. Otherwise returns true.

For example:

-----------------------------------------------------
: show-model-name ( -- ) " model" get-my-property 0= if ( val.addr len ) ." model name is " type cr else ( ) ." model property is missing " cr then ( ) ; -----------------------------------------------------
get-package-
property
( name-str name-len phandle -- true | prop-addr prop-len false ) 02 1F

Locates, in the package phandle, the property named by name-addr name-len. If the property exists, returns the property value array prop-addr prop-len and false. Otherwise returns true.

For example:

--------------------------------------------------------------
: show-model-name ( -- ) my-self ihandlephandle ( phandle ) " model" rot get-package-property 0= if ( val.addr len ) ." model name is " type cr else ( ) ." model property is missing " cr then ( ) ; --------------------------------------------------------------
get-token
( fcode# -- xt immediate? ) DA

Returns the execution token xt of the word associated with FCode number fcode# and a flag immediate? that is true if and only if that word will be executed (rather than compiled) when the FCode Evaluator encounters its FCode number while in compilation state.

h# number ( -- )
10 xx xx xx xx xx xx xx xx b(lit) value

Causes the compiler/interpreter to interpret the immediately following number as a hexadecimal number (base sixteen), regardless of any previous settings of hex, or decimal. Only the immediately following number is affected. The value of base is unchanged.

For example:

-------------------------------
decimal h# 100 ( equals decimal 256 ) 100 ( equals decimal 100 ) -------------------------------

See also: d#

.h
( n -- ) a0 6d 49 10 00 00 00 10 a0 72 9d a0 72 base @ swap d# 16 base ! . base !

Displays n in hex (using . ) The value of base is not permanently affected.

headerless
( -- ) none

Causes all subsequent FCode definitions to be created without the name field (the "head"). (See named-token and new-token.) This is sometimes done to save space in the final FCode PROM, or possibly to make it more difficult to reverse-engineer an FCode Program.

All such headerless words can be used normally in the FCode Program, but cannot be called interactively from the User Interface for testing and development purposes.

Unless PROM space and/or dictionary space is a major consideration, try not using headerless words, because they make debugging more difficult.

headerless remains in effect until headers or external is encountered.

For example:

--------------------------
headerless h# 3 constant reset-scsi --------------------------
headers
( -- ) none

Causes all subsequent definitions to be saved with the name field (the "head") intact. This is the initial default behavior.

Note that even normal FCode words (with heads) cannot be called interactively from the User Interface unless the NVRAM parameter fcode- debug? has been set to true before a system reset.

headers remains in effect until headerless or external is encountered.

For example:

--------------------------
headers : cnt@ ( -- w ) transfer-count-lo rb@ transfer-count-hi rb@ bwjoin ; --------------------------
here
( -- addr ) AD

here returns the address of the next available dictionary location.

hex
( -- ) 10 00 00 00 10 a0 72 b(lit) 16 base !

If used outside of a definition, commands the tokenizer program to interpret subsequent numbers in hex (base 16). If used in a definition, changes the value in base affecting later numeric output when the FCode Program is executed.

See also: base

hold
( char -- ) 95

Inserts char into a pictured numeric output string. Typically used between <# and #'>.

For example:

--------------------------------------------
: .32 ( n -- ) base @ r hex <# # # # # ascii . hold # # # # # type r base ! space ; --------------------------------------------
i
( -- index ) ( R: sys -- sys ) 19

index is a copy of the loop index. May only be used inside of a do or ?do loop.

For example:

----------------------------------
: simple-loop ( start len -- ) bounds ?do i .h cr loop ; ----------------------------------
if
( C: -- orig-sys ) ( do-next? -- ) 14 +offset b?branch +offset

Execute the following code if do-next? is true. Used in the form:

-----------------------
do-next? if...else...then -----------------------

or

------------------
do-next? if...then ------------------

If do-next? is true, the words following if are executed and the words following else are skipped. The else part is optional. If do-next? is false, words from if through else, or from if through then (when no else is used), are skipped.

ihandlephandle
( ihandle -- phandle ) 02 0B

Returns the phandle of the package from which the instance ihandle was created. This is often used with get-package-property to read the properties of the package corresponding to a given ihandle.

For example:

------------------------------------------
: show-parent ( -- ) my-parent ihandlephandle " name" rot get-package-property 0= if ." my-parent is " type cr then ; ------------------------------------------
insert-characters
( n -- ) 01 5D

insert-characters is one of the defer words of the display device interface. The terminal emulator package executes insert-characters when it has processed a character sequence that calls for opening space for characters to the right of the cursor. Without moving the cursor, insert- characters moves the remainder of the line to the right, thus losing the n rightmost characters in the line, and fills the n vacated character positions with the background color.

This word is initially empty, but must be loaded with an appropriate routine in order for the terminal emulator to function correctly. This can be done with to, or it can be loaded automatically with fb1-install or fb8-install (which loads fb1-insert-characters or fb8-insert-characters, respectively).

insert-lines
( n -- ) 01 5F

insert-lines is one of the defer words of the display device interface. The terminal emulator package executes insert-lines when it has processed a character sequence that calls for opening space for lines of text below the cursor. Without moving the cursor, insert-lines moves the cursor line and all following lines down, thus losing the n bottom lines. and fills the n vacated lines with the background color.

This word is initially empty, but must be loaded with an appropriate routine in order for the terminal emulator to function correctly. This can be done with to, or it can be loaded automatically with fb1-install or fb8-install (which loads fb1-insert-lines or fb8-insert-lines, respectively).

instance
( -- ) C0

Modifies the next occurrence of value, variable, defer or buffer: to create instance-specific data instead of static data. Re-allocates the data each time a new instance of this package is created.

For example:

-------------------------------
-1 instance value my-chip-reg -------------------------------
inverse?
( -- white-on-black? ) 01 54

This value is part of the display device interface. The terminal emulator package sets inverse? to true when the escape sequences that it has processed have indicated that subsequent characters are to be shown with foreground and background colors exchanged, and to false, indicating normal foreground and background colors, otherwise.

The fb1- and fb8- frame buffer support packages draw characters with foreground and background colors exchanged if inverse? is true, and with normal foreground and background colors if inverse? is false.

inverse? affects the character display operations draw-character, insert-characters, and delete-characters, but not the other operations such as insert-lines, delete-lines and erase-screen.

inverse-screen? should be monitored as needed if your FCode Program is implementing its own set of frame buffer primitives.

See also: inverse-screen?

inverse-screen?
( -- black? ) 01 55

This value is part of the display device interface. The terminal emulator package sets inverse-screen? to true when the escape sequences that it has processed have indicated that the foreground and background colors are to be exchanged for operations that affect the background, and to false, indicating normal foreground and background colors, otherwise.

The fb1- and fb8- frame buffer support packages perform screen drawing operations other than character drawing operations with foreground and background colors exchanged if inverse-screen? is true, and with normal foreground and background colors is false.

inverse-screen? affects background operations such as insert-lines, delete-lines and erase-screen, but not character display operations such as draw-character, insert-characters and delete-characters.

When inverse-screen? and inverse? are both true, the colors are exchanged over the entire screen, and subsequent characters are not highlighted with respect to the (inverse) background. For exchanged screen colors and highlighted characters, the setting are inverse-screen? true and inverse? false.

inverse-screen? should be monitored as needed if your FCode Program is implementing its own set of frame buffer primitives.

invert
( x1 -- x2 ) 26

x2 is the one's complement of x1 i.e. all the one bits in x1 are changed to zero, and all the zero bits are changed to one.

For example:

------------------------------------
: clear-lastbit ( -- ) my-reg rl@ 1 not and my-reg rl! ; ------------------------------------

See also 0=.

invert-screen
( -- ) 01 5C

invert-screen is one of the defer words of the display device interface. The terminal emulator package executes invert-screen when it has processed a character sequence that calls for exchanging the foreground and background colors (e.g. changing from black-on-white to white-on-black).

invert-screen changes all pixels on the screen so that pixels of the foreground color are given the background color, and vice versa, leaving the colors that will be used by subsequent text output unaffected.

This word is initially empty, but must be loaded with an appropriate routine in order for the terminal emulator to function correctly. This can be done with to, or it can be loaded automatically with fb1-install or fb8-install (which loads fb1-invert-screen or fb8-invert-screen, respectively).

is-install
( xt -- ) 01 1C

Creates open, write, and draw-logo methods for display devices.

For any SBus frame buffer that is to be used by the boot PROM before or during booting, is-install declares the FCode procedure that should be used to install (i.e. initialize) that frame buffer. Note that this is distinct from any once-only power-on initialization that should be performed during the probing process itself.

The is-install routine and is-remove routine should comprise a matched pair that may be performed alternately as many times as needed. Typically, the is-install routine performs mapping functions and some initialization, and the is-remove performs any cleanup functions and then does a complementary unmapping.

A partial, typical code example follows:

---------------------------------------------------------------
version1 ... : power-on ( -- ) \ Once-only, power-on initialization map-register init-register unmap-register ; ... : map-devices ( -- ) \ Map register and buffer map-register map-buffer ; ... : install-me ( -- ) \ Do this to start using this device map-devices initialize-devices ; : remove-me ( -- ) \ Do this to stop using this device reset-buffers unmap-devices ; ... \ This routine executed during the probe of this FCode : my-probe ( -- ) \ First, define the routine power-on \ Power-on initialization ['] install-me is-install \ Declare "install" routine ['] remove-me is-remove \ Declare "remove" routine ['] test-me is-selftest \ Declare "selftest" routine ; \ End of the defintion my-probe \ Now execute the routine end0 ---------------------------------------------------------------
is-remove
( xt -- ) 01 1D

Creates a close method for display devices that will de-allocate a frame buffer that is no longer going to be used. Typical de-allocation would include unmapping memory and clearing buffers. For example:

----------------------------------------------------------
version1 ... : remove-me ( -- ) \ Do this to stop using this device reset-buffers unmap-devices ; ... \ This routine executed during the "probe" of this FCode : my-probe ( -- ) \ First, define the routine power-on \ Power-on initialization ['] install-me is-install \ Declare "install" routine ['] remove-me is-remove \ Declare "remove" routinea ['] test-me is-selftest \ Declare "selftest" routine ; \ End of the definition my-probe \ Now, execute this routine end0 ----------------------------------------------------------

The routine loaded with is-remove should form a matched pair with the routine loaded with is-install. See is-install for more details.

is-selftest
( xt -- ) 01 1E

Creates a selftest method for display devices that will perform a self test of the frame buffer. For example:

----------------------------------------------------------
version1 ... : test-me ( -- fail? ) \ self test method ... ; ... \ This routine executed during the "probe" of this FCode : my-probe ( -- ) \ First, define the routine power-on \ Power-on initialization ['] install-me is-install \ Declare "install" routine ['] remove-me is-remove \ Declare "remove" routine ['] test-me is-selftest \ Declare "selftest" routine ; \ End of the definition my-probe \ Now, execute this routine end0 ----------------------------------------------------------

This declaration is typically performed in the same place in the code as is- install and is-remove.

The self test routine should return a status parameter on the stack indicating the results of the test. A zero value indicates that the test passed. Any nonzero value indicates that the self test failed, but the actual meaning for any nonzero value is not specified. (memory-test-suite returns a flag meeting these specifications.)

selftest is not automatically executed. For automatic testing, devices should perform a quick sanity check as part of the install routine. See "selftest" on page 52.

(is-user-word)
( E: ... -- ??? ) ( name-str name-len xt -- ) 02 14

Creates a Forth word (not a package method) whose name is given by name-str name-len and whose behavior is given by the execution token xt which must refer to a static method. This allows an FCode Program to define new User Interface commands.

For example:

-------------------------------------
" xyz-abort" ' my-abort (is-user-word) -------------------------------------
j
( -- index ) ( R: sys -- sys ) 1A

index is a copy of the index of the next outer loop. May only be used in a nested do or ?do loop. For example:

-------------------
do ... do ... j ... loop ... loop -------------------

Usually, do loops should not be nested this deeply inside a single definition. Forth programs are generally more readable if inner loops are defined inside a separate word.

key
( -- char ) 8E

A defer word that reads the next ASCII character from the keyboard. If no character has been typed since key or expect was last executed, key waits until a new character is typed. All valid ASCII characters can be received. Control characters are not processed by the system for any editing purpose. Characters received by key are not displayed.

For example:

--------------------------------------------------
: continue? ( -- continue? ) ." Want to Continue? Enter Y/N" key dup emit dup ascii Y = ascii y rot = or ; --------------------------------------------------

See also: key?

key?
( -- pressed? ) 8D

A defer word returning true if a character has been typed on the keyboard since the last time that key or expect was executed. The keyboard character is not consumed.

Use key? to make simple, interruptible infinite loops:

--------------------
begin ... key? until --------------------

The contents of the loop will repeat indefinitely until any key is pressed.

See also: key

l!
( quad qaddr -- ) 73

The 32-bit value quad is stored at location qaddr. qaddr must be 32-bit aligned.

See also: rl!

l,
( quad -- ) D2

Compile a 32-bit number into the dictionary. The dictionary pointer must be 2-byte-aligned.

For example:

-----------------------------------------------------------
\ to create an array containing integers 40004000 23 45 6734 create my-array 40004000 l, 23 l, 45 l, 6734 l, -----------------------------------------------------------
l@
( qaddr -- quad ) 6E

Fetch the 32-bit number stored at qaddr. qaddr must be 32-bit aligned.

See also: rl@

/l
( -- n ) 5C

n is the number of address units to a 32-bit word, typically 4.

/l*
( nu1 -- nu2 ) 68

nu2 is the result of multiplying nu1 by /l. This is the portable way to convert an index into a byte offset.

la+
( addr1 index -- addr2 ) 60

Increments addr1 by index times the value of /l. This is the portable way to increment an address.

la1+
( addr1 -- addr2 ) 64

Increments addr1 by the value of /l. This is the portable way to increment an address.

lbflip
( quad1 -- quad2 ) 02 27

Reverse the bytes in a 32-bit datum.

lbflips
( qaddr len -- ) 02 28

Reverse the bytes in each 32-bit datum in the given region.

The region begins at qaddr and spans len bytes. The behavior is undefined if len is not a multiple of /l.

lbsplit
( quad -- byte1.lo byte2 byte3 byte4.hi ) 7E

Splits a 32-bit datum into four bytes. The high bytes of each stack result are all zeroes.

lcc
( char1 -- char2 ) 82

char2 is the lower case version of char1. If char1 is not an upper case letter, it is unchanged. For example:

----------------------
ok ascii M lcc emit m ok ----------------------

See also: upc

leave
( -- ) ( R: sys -- ) 1b b(leave)

Transfers execution to just past the next loop or +loop. The loop is terminated and loop control parameters are discarded. May only be used in a do or ?do loop.

leave may appear in other control structures that are nested in the do loop structure. More than one leave may appear in a do loop.

For example:

----------------------------------------------------
: search-pat ( pat addr len -- found? ) rot false swap 2swap ( false pat addr len ) bounds ?do ( flag pat ) i @ over = if drop true swap leave then loop drop ; ----------------------------------------------------

See also: exit, unloop

?leave
( exit? -- ) ( R: sys -- ) 14 + offset 1b b2 if leave then

If exit? is true (nonzero), ?leave transfers control to just beyond the next loop or +loop. The loop is terminated and loop control parameters are discarded. If exit? is zero, no action is taken. May only be used in a do or ?do loop.

?leave may appear in other control structures that are nested in the do loop structure. More than one ?leave may appear in a do loop.

For example:

--------------------------------------------------------------
: show-mem ( vaddr -- ) \ display h# 10 bytes dup h# 9 u.r 5 spaces h# 10 bounds do i c@ 3 u.r loop ; : .mem ( vaddr size -- ) bounds ?do i show-mem key? ?leave h# 10 +loop ; --------------------------------------------------------------
left-parse-string
( str len char -- R-str R-len L-str L-len ) 02 40

Splits the input string at the first occurrence of delimiter char. For example:

----------------------------------------
" test;in;g" ascii ; left-parse-string ----------------------------------------

would leave the address and length of two strings on the stack:

"in;g" and "test".

The delimiter character may be any ASCII character. Note that if the delimiter is not found in the string, the effect is as if the delimiter was found at the very end. For example:

--------------------------------------
" testing" ascii q left-parse-string --------------------------------------

would leave on the stack "" and "testing".

line#
( -- line# ) 01 52

A value, set and controlled by the terminal emulator, that contains the current cursor line number. A value of 0 represents the topmost line of available text space - not the topmost pixel of the frame buffer.

This word should be monitored as needed if your FCode Program is implementing its own set of frame buffer primitives.

For example:

----------------------------------------------------------
: set-line ( line -- ) 0 max #lines 1- min to line# ; ----------------------------------------------------------

See also: window-top

#line
( -- a-addr ) 94

A variable containing the number of output lines since the last user interaction i.e. since the last ok prompt. #line is incremented whenever cr executes. The value in this variable is used to determine when to pause during long display output, such as dump. Its value is reset each time the ok prompt displays.

See also: exit?

linefeed
( -- 0x0A ) 10 00 00 00 0a b(lit) 00 00 00 0x0A

Leaves the ASCII code for the linefeed character on the stack.

#lines
( -- rows ) 01 50

#lines is a value that is part of the display device interface. The terminal emulator package uses it to determine the height (number of rows of characters) of the text region that it manages. The fb1- and fb8- frame buffer support packages also use it for a similar purpose.

The value of #lines must be set to the desired height of the text region. This can be done with to, or it can be handled automatically as one of the functions performed by fb1-install or fb8-install. The value set by fbx- install is the smaller of the passed #lines parameter and the screen- #rows NVRAM parameter.

For example:

----------------------------------------------------------
: set-line ( line -- ) 0 max #lines 1- min to line# ; ----------------------------------------------------------
loop
( C: dodest-sys -- ) ( -- ) ( R: sys1 -- <nothing | sys2 ) 15 -offset b(loop) -offset

Terminates a do or ?do loop. Increments the loop index by one. If the index was incremented across the boundary between limit-1 and limit, the loop is terminated and loop control parameters are discarded. When the loop is not terminated, execution continues just after the corresponding do or ?do.

For example, the following do loop:

-------------
8 0 do...loop -------------

terminates when the loop index changes from 7 to 8. Thus, the loop will iterate with loop index values from 0 to 7, inclusive.

loop may be used either inside or outside of colon definitions.

+loop
( C: dodest-sys -- ) ( n -- ) ( R: sys1 -- <nothing | sys2 ) 16 -offset b(+loop) -offset

Terminates a do or ?do loop. Increments the loop index by n (or decrements the index if n is negative). If the index was incremented (or decremented) across the boundary between limit-1 and limit the loop is terminated and loop control parameters are discarded. When the loop is not terminated, execution continues just after the corresponding do or ?do.

The following do loop:

----------------
8 0 do...2 +loop ----------------

terminates when the loop index crosses the boundary between 7 and 8. Thus, the loop will iterate with loop index values of 0, 2, 4, 6.

By contrast, a do loop created as follows:

-----------------
0 8 do...-2 +loop -----------------

terminates when the loop index crosses the boundary between -1 and 0. Thus, the loop will iterate with loop index values of 8, 6, 4, 2, 0.

+loop may be used either inside or outside of colon definitions.

lpeek
( qaddr -- false | quad true ) 02 22

Tries to read the 32-bit word at address qaddr. Returns quad and true if the access was successful. A false return indicates that a read access error occurred. qaddr must be 32-bit aligned.

lpoke
( quad qaddr -- okay? ) 02 25

Tries to write quad at address qaddr. Returns true if the access was successful. A false return indicates a write access error. qaddr must be 32-bit aligned.

Note - lpoke may be unreliable on bus adapters that "buffer" write accesses.

lshift
( x1 u -- x2 ) 27

Shifts x1 left by u bit-places. Zero-fills the low bits.

lwflip
( quad1 -- quad2 ) 02 26

Swaps the doublets in a quadlet.

lwflips
( qaddr len -- ) 02 37

Swaps the order of the 16-bit words in each 32-bit word in the memory buffer qaddr len. qaddr must be four-byte-aligned. len must be a multiple of /l.

For example:

-------------------------
ok h# 12345678 8000 l! ok 8000 4 lwflips ok 8000 l@ .h 56781234 -------------------------
lwsplit
( quad -- w1.lo w2.hi ) 7C

Splits the 32-bit value quad into two 16-bit words. The upper bytes of the two generated words are zeroes.

mac-address
( -- mac-str mac-len ) 01 A4

Usually used only by the "network" device type, this FCode returns the value for the Media Access Control, or MAC address, that this device should use for its own address. The data is encoded as a byte array, generally 6 bytes long.

The value returned by mac-address is system-dependent.

See also: "mac-address", "local-mac-address", and "network" in Chapter 5, "Properties" and Chapter 9, "Network Devices".

map-low
( phys.lo ... size -- virt ) 01 30

Creates a mapping associating the range of physical addresses beginning at phys.lo ... my-space and extending for size bytes in this device's physical address space with a processor virtual address. Return that virtual address virt.

Equivalent to:

--------------------------------------
my-space swap " map-in" $call-parent --------------------------------------

The number of cells in the list phys.lo ... is one less than the number determined by the value of the "#address-cells" property of the parent node.

If the requested operation cannot be performed, throw is called with an appropriate error message.

Out-of-memory conditions can be detected and handled with the phrase:
['] map-low catch

See also: map-out

mask
( -- a-addr ) 01 24

This variable defines which bits out of every 32-bit word will be tested by memory-test-suite. To test all 32-bits, set mask to all ones with:

------------------
ffff.ffff mask ! ------------------

To test only the low-order byte out of each word, set the lower bits of mask with:

------------------
0000.00ff mask ! ------------------

Any arbitrary combination of bits can be tested or masked.

max
( n1 n2 -- n1|n2 ) 2F

Returns the greater of n1 and n2.

memory-test-suite
( addr len -- fail? ) 01 22

Performs a series of tests on the memory beginning at addr for len bytes. If any of the tests fail, failed? is true and a failure message is displayed on a system-dependent diagnostic output device.

The actual tests performed are machine specific and often vary depending on whether diagnostic-mode? is true or false. Typically, if diagnostic- mode? is true, a message is sent to the console output device giving the name of each test.

The value stored in mask controls whether only some or all data lines are tested.

For example:

-------------------------------------------------------------------
: test-result ( -- ) frame-buffer-adr my-frame-size memory-test-suite ( failed? ) encode-int " test-result" property ; -------------------------------------------------------------------

See also: diag-switch?

min
( n1 n2 -- n1|n2 ) 2E

Returns the lesser of n1 and n2.

mod
( n1 n2 -- rem ) 22

rem is the remainder after dividing n1 by the divisor n2. rem has the same sign as n2 or is zero. An error condition results if the divisor is zero.

*/mod
( n1 n2 n3 -- rem quot ) 30 20 31 2a

Calculates n1 * n2 / n3 and returns the remainder and quotient. The inputs, outputs, and intermediate products are all 32-bit. rem has the same sign as n3 or is zero. An error condition results if the divisor is zero.

/mod
( n1 n2 -- rem quot ) 2A

rem is the remainder and quot is the quotient of n1 divided by the divisor n2. rem has the same sign as n2 or is zero. An error condition results if the divisor is zero.

model
( str len -- ) 01 19

This is a shorthand word for creating a "model" property. By convention, "model" identifies the model name/number for a SBus card, for manufacturing and field-service purposes. A sample usage would be:

---------------------------
" SUNW,501-1415-1" model ---------------------------

This is equivalent to:

------------------------------------------------------
" SUNW,501-1415-1" encode-string " model" property ------------------------------------------------------

The "model" property is useful to identify the specific piece of hardware (the SBus card), as opposed to the "name" property (since several different but functionally-equivalent cards would have the same "name" property, thus calling the same operating system device driver).

See also: property, "model" in Chapter 5, "Properties".

move
( src_addr dest_addr len -- ) 78

len bytes starting at src_addr (through src_addr+len-1 inclusive) are moved to address dest_addr (through dest_addr+len-1 inclusive). If len is zero then nothing is moved.

The data are moved such that the len bytes left starting at address dest_addr are the same data as was originally starting at address src_addr. If src_addr dest_addr then the first byte of src_addr is moved first, otherwise the last byte (src_addr+len-1) is moved first. Thus, moves between overlapping fields are properly handled.

move will perform 16-bit, 32-bit or possibly even 64-bit operations (for better performance) if the alignment of the operands permits. If your hardware requires explicit 8-bit or 16-bit accesses, you will probably wish to use an explicitly-coded do ... loop instead.

ms
( n -- ) 01 26

Delays all execution for at least n milliseconds, by executing an empty delay loop for an appropriate number of iterations. The maximum allowable delay will vary from system to system, but is guaranteed to be valid for all values up to at least 1,000,000 (decimal). No other CPU activity takes place during delays invoked with ms, although generally this is not a problem for FCode drivers since there is nothing else to do in the meantime anyway. If this word is used excessively, noticeable delays could result.

For example:

------------------------------------------------------------
: probe-loop-wait ( addr -- ) \ wait h# 10 ms before doing another probe at the location begin dup l@ drop h# 10 ms key? until drop ; ------------------------------------------------------------
my-address
( -- phys.lo ... ) 01 02

Returns the low component(s) of the device's probe address, suitable for use with the map-in method, and with reg and encode-phys. The returned number, along with my-space, encodes the address of location 0 of this device in a bus-specific format. The number of cells in the list phys.lo ... is one less than the number determined by the value of the "#address-cells" property of the parent node.

The OpenBoot PROM automatically sets my-address to the correct value before each slot is probed. Usually, this value is used to calculate the location(s) of the device registers, which are then saved as the property value of the "reg" property and later accessed with my-unit.

For example for a SBus device:

------------------------------------------------------------------------
fcode-version2 " audio" encode-string " name" property my-address my-space encode-phys \ SBus Configuration Space 0 encode-int encode+ 0 encode-int encode+ ... " reg" property end0 ------------------------------------------------------------------------
my-args
( -- arg-str arg-len ) 02 02

Returns the instance argument string arg-str arg-len that was passed to the current instance when it was created, if the argument string exists. Otherwise returns with a length of 0.

For example:

----------------------------------------------
ok " /obio:TEST-ARGS" open-dev my-args type TEST-ARGS ----------------------------------------------
my-parent
( -- ihandle ) 02 0A

Returns the ihandle of the instance that opened the current instance. For device driver packages, the relationships of parent/child instances mimic the parent/child relationships in the device tree.

For example for an SBus device:

------------------------------------------
: show-parent ( -- ) my-parent ihandlephandle " name" rot get-package-property 0= if ." my-parent is " type cr then ; ------------------------------------------
my-self
( -- ihandle ) 02 03

A value word that returns the current instance's ihandle. If there is no current instance, the value returned is zero.

For example:

--------------------------------------------------------------
: show-model-name ( -- ) my-self ihandlephandle ( phandle ) " model" rot get-package-property 0= if ( val.addr,len ) ." model name is " type cr else ( ) ." model property is missing " cr then ( ) ; --------------------------------------------------------------
my-space
( -- phys.hi ) 01 03

Returns the high component of the device's probe address representing the device space that this card is plugged into. The meaning of the returned value is bus-specific.

For example for an SBus device:

-----------------------------------------------
fcode-version1 " audio" encode-string " name" property my-address h# 130.0000 + my-space h# 8 reg ... end0 -----------------------------------------------

See my-address for more details.

my-unit
( -- phys.lo ... phys.hi ) 02 0D

Returns the unit address phys.lo ... phys.hi of the current instance. The unit address is set when the instance is created, as follows:

The number of cells in the list phys.lo ... phys.hi is determined by the value of the "#address-cells" property of the parent node.

/n
( -- n ) 5D

The number of address units in a cell.

/n*
( nu1 -- nu2 ) 69 cells

Synonym for cells.

na+
( addr1 index -- addr2 ) 61

Increments addr1 by index times the value of /n.

na+ should be used in preference to wa+ or la+ when the intent is to address items that are the same size as items on the stack.

na1+
( addr1 -- addr2 ) 65 cell+

Synonym for cell+.

name
( adr len -- ) 1 14 12 04 6e 61 6d 65 1 10 encode-string" name" property

A shorthand word for creating a "name" property, used to match a device node with the appropriate Solaris driver. The "name" declaration is required for booting with Solaris, and should be present in every FCode program. For example:

--------------------
" SUNW,bison" name --------------------

is equivalent to:

---------------------------------------------
" SUNW,bison" encode-string" name" property ---------------------------------------------

See also property, device-name.

See "name" in Chapter 5, "Properties".

named-token
( -- ) ( F: /FCode-string FCode#/ -- ) B6

Creates a new, possibly-named FCode function. named-token should never be used directly in source code.

negate
( n1 -- n2 ) 2C

n2 is the negation of n1. This is equivalent to 0 swap - .

new-device
( -- ) 01 1F

Starts a new entry in the device tree. This word is used for creating multiple devices in a single FCode Program.

See also: finish-device

new-token
( -- ) ( F: /FCode#/ -- ) B5

Creates a new unnamed FCode function. new-token should never be used directly in source code.

next-property
( previous-str previous-len phandle -- false | name-str name-len true ) 02 3D

Returns the name of the property following previous-string of phandle.

name-string is a null-terminated string that is the name of the property following previous-string in the property list for device phandle. If previous-string is zero or points to a zero-length string, name-string is the name of phandle's first property. If there are no more properties after previous-string or if previous-string is invalid (i.e. names a property which does not exist in phandle), name-string is a pointer to a zero-length string.

nip
( x1 x2 -- x2 ) 4D

Removes the second item on the stack.

noop
( -- ) 7B

Does nothing. This can be used to provide short delays or as a placeholder for patching in other commands later.

not
( x1 -- x2 ) 26 invert

Synonym for invert.

See also: 0=

$number
( addr len -- true | n false ) A2

A numeric conversion primitive that converts a string to a number, according to the current base value. An error flag is returned if an inconvertible character is encountered.

For example:

------------------------
ok hex ok " 123f" $number .s 123f 0 ok " 123n" $number .s ffffffff ------------------------
octal
( -- ) 10 00 00 00 08 90 72

If octal is encountered by the tokenizer in FCode Source outside a definition, the tokenizer sets its numeric conversion radix to eight.

If octal is encountered by the tokenizer in FCode Source inside a definition, the tokenizer appends the following sequence to the FCode Program that is being created: 8 base ! This affects numeric output when the FCode Program is later executed.

See also: base

of
( C: case-sys1 -- case-sys2 of-sys ) ( sel of-val -- set | <nothing ) 1C +offset b(of) +offset

Begins the next test clause in a case statement. See case for more details.

off
( a-addr -- ) 6B

Sets the 32-bit contents at a-addr to false (i.e. zero).

offset16
( -- ) CC

Instructs the tokenizer program, and the boot PROM, to expect all further branch offsets to be 16-bit values. This word is automatically generated by some current tokenizers.

Once offset16 is executed, the offset size remains 16 bits for the duration of the FCode Program; it cannot be set back to 8 bits. Multiple calls of offset16 have no additional effect. offset16 is only useful in an FCode Program that begins with version1. All other starting tokens (start0, start1, start2, and start4) automatically set the offset size to 16 bits.

See also: fcode-version2

on
( a-addr -- ) 6A

Set the 32-bit contents at a-addr to true (i.e. ffffffff).

open-package
( arg-str arg-len phandle -- ihandle | 0 ) 205

Creates an instance of the package identified by phandle, saves in that instance an argument string specified by arg-str arg-len, and invokes the package's open method. The parent instance of the new instance is the instance that invoked open-package.

Returns the instance handle ihandle of the new instance if it can be opened. It returns 0 if the package could not be opened, either because that package has no open method or because its open method returned false indicating an error. In this case, the current instance is not changed.

For example:

----------------------------------------------------------
: test-tftp-open ( -- ok? ) " obp-tftp" find-package if ( phandle ) 0 0 rot open-package if true else false then else false then ; ----------------------------------------------------------
$open-package
( arg-str arg-len name-str name-len -- ihandle | 0 ) 02 0F

Similar to using find-package open-package except that if find- package fails, 0 is returned immediately, without calling open-package.

The name is interpreted relative to the /packages device node. For example, if name-str name-len represents the string "disk-label", the package in the device tree at "/packages/disk-label" will be located.

If there are multiple packages with the same name (in the /packages node), the most recently created one is opened.

For example:

---------------------------------------------
0 0 " obp-tftp" $open-package ( ihandle ) ---------------------------------------------
or
( x1 x2 -- x3 ) 24

n3 is the bit-by-bit inclusive-or of n1 with n2.

#out
( -- a-addr ) 93

A variable containing the current column number on the output device. This is updated by emit, cr and some other words that modify the cursor position. It is used for display formatting.

For example:

-------------------------------------------------------
: to-column ( column -- ) #out @ - 1 max spaces ; -------------------------------------------------------
over
( x1 x2 -- x1 x2 x1 ) 48

The second stack item is copied to the top of the stack.

2over
( x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2 ) 54

Copies the third and fourth stack items to the stack top.

pack
( str len addr -- pstr ) 83

Stores the string specified by str len as a packed string at the location addr returning pstr (which is the same address as addr). The byte at address pstr is the length of the string and the string itself starts at address pstr+1. A packed string can contain at most 255 characters.

Packed strings are generally not used in FCode. Virtually all string operations are in the addr len format.

For example:

------------------------------------------------
h# 20 buffer: my-packed-string " This is test string " my-packed-string pack ------------------------------------------------
parse-2int
( str len -- val.lo val.hi ) 01 1B

Converts a "hi,lo" string into a pair of values according to the current value in base.

If the string does not contain a comma, val.lo is zero and val.hi is the result of converting the entire string. If either component contains non-numeric characters, according to the value in base, the result is undefined.

For example:

---------------------------------
ok " 4,ff001200" parse-2int .s ff001200 4 ok " 4" parse-2int .s 0 4 ---------------------------------
peer
( phandle -- phandle.sibling ) 02 3C

peer returns the phandle phandle.sibling of the package that is the next child of the parent package phandle.

If there are no more siblings, peer returns 0.

If phandle is 0, peer returns phandle of the root node.

Together with child, peer lets you enumerate (possibly recursively) the children of a particular device. A common application would be for a device driver to use child to determine the phandle of a node's first child, and use peer multiple times to determine the phandles of the node's other children. For example:

--------------------------------------------------
: my-children ( -- ) my-self ihandlephandle child ( first-child ) begin ?dup while dup . peer repeat ; --------------------------------------------------
pick
( xu ... x1 x0 u -- xu ... x1 x0 xu ) 4E

Copies the u-th stack value, not including u itself, where the remaining stack items have indices beginning with 0. u must be between 0 and two less than the total number of elements on the stack (including u).

------------------------------------------------------
0 pick is equivalent to dup ( n1 -- n1 n1 ) 1 pick is equivalent to over ( n1 n2 -- n1 n2 n1 ) 2 pick is equivalent to ( n1 n2 n3 -- n1 n2 n3 n1 ) ------------------------------------------------------

For the sake of readability, the use of pick should be minimized.

property
( prop-addr prop-len name-str name-len -- ) 110

Creates a new property with the specified name and previously prop-encoded value. If there is a current instance, creates the property in the package from which the current instance was created. Otherwise, if there is an active package, creates the property in the active package. If there is neither a current instance nor an active package, the result is undefined.

If a property with the specified name already exists in the active package in which the property would be created, replace its value with the new value.

Properties provide a mechanism for an FCode Program to pass information to an operating system device driver. A property consists of a property name string and a property value array. The name string gives the name of the property, and the value array gives the value associated with that name. For example, a frame buffer may wish to declare a property named "hres" (for horizontal resolution) with a value of 1152.

The property command requires two arrays on the stack - the value array and the name string. The name string is an ordinary Forth string, such as any string created with " . This string should be written in lower case, since the property name is stored only after converting uppercase letters, if any, to lower case. For example:

------------------------------------------------
" A21-b" encode-string " New_verSION" property ------------------------------------------------

is stored as if entered

------------------------------------------------
" A21-b" encode-string " new_version" property ------------------------------------------------

The value array, however, must be in the property value array format. See Chapter 5, "Properties" for more information on creating property value arrays.

All properties created by an FCode Program are stored in a "device tree" by OpenBoot. This tree can then be queried by an operating system device driver, using the Client Interface's getprop or nextprop services.

The FCode Program and the operating system device driver may agree on any arbitrary set of names and values to be passed, with virtually no restrictions. Several property names, though, are reserved and have specific meanings. For many of them, a shorthand command also exists that makes the property declaration a bit simpler.

For example:

----------------------------------------
" SUNW,new-model" encode-string model ----------------------------------------

See also: "name", device-name, model, reg and Chapter 5, "Properties" for more information.

r'>
( -- x ) ( R: x -- ) 31

Removes x from the return stack and places it on the stack. See >r for restrictions on the use of this word.

For example:

--------------------------------------------------------
: copyout ( buf addr len -- len ) r swap r@ move r ; --------------------------------------------------------
r@
( -- x ) ( R: x -- x ) 32

Places a copy of the top of the return stack on the stack.

For example:

--------------------------------------------------------
: copyout ( buf addr len -- len ) r swap r@ move r ; --------------------------------------------------------

See >r for more details.

.r
( n size -- ) 9E

Converts n using the value of base and then displays it right-aligned in a field size digits wide. Displays a leading minus sign if n is negative. A trailing space is not displayed.

If the number of digits required to display n is greater than size, displays all the digits required with no leading spaces in a field as wide as necessary.

For example:

---------------------------------------
: formatted-output ( -- ) my-length h# 8 .r ." length" cr my-width h# 8 .r ." width" cr my-depth h# 8 .r ." depth" cr ; ---------------------------------------
>r
( x -- ) ( R: -- x ) 30

Removes x from the stack and places it on the top of the return stack.

The return stack is a second stack, occasionally useful as a place to temporarily place numeric parameters i.e. to "get them out of the way" for a little while. For example:

-------------------------------------------------------
: encode-intr ( int-level vector -- ) r sbus-intrcpu encode-int r encode-int encode+ ; -------------------------------------------------------

However, since the return stack is also used by the system for transferring control from word to word (and by do loops), improper use of >r or r'> is guaranteed to crash your program. Some restrictions that must be observed are:

rb!
( byte addr -- ) 02 31

Stores an 8-bit byte to a device register at addr with identical bit ordering as the input stack item. Data is stored with a single access operation and flushes any intervening write buffers, so that the data reaches its final destination before the next FCode Function is executed.

For example:

---------------------------------------
: my-stat! ( byte -- ) my-stat rb! ; ---------------------------------------
rb@
( addr -- byte ) 02 30

Fetches byte from the device register at addr. Data is read with a single access operation. The result has identical bit ordering as the original register data.

For example:

--------------------------------------
: my-stat@ ( -- byte ) my-stat rb@ ; --------------------------------------
reg
( phys.lo ... phys.hi size -- ) 01 16

This is a shorthand word for declaring the "reg" property. Typical usage for an SBus device:

-----------------------------------------
my-address 40.0000 + my-space 20 reg -----------------------------------------

This declares that the device registers are located at offset 40.0000 through 40.001f in this slot. The following code would accomplish the same thing:

--------------------------------------------
my-address 40.0000 + my-space encode-phys 20 encode-int encode+ " reg" property --------------------------------------------

Note that if you need to declare more than one block of register addresses, you must repeatedly use encode-phys, encode-int and encode+ to build the structure to be passed into the "reg" property.

For example, to declare two register fields at 10.0000-10.00ff and 20.0000- 20.037f on a SBus device, use the following:

---------------------------------------------------------------------
my-address my-space encode-phys \ Config space regs 0 encode-int encode+ 0 encode-int encode+ my-address 10.0000 0 d+ my-space encode-phys \ Offset#1 0 encode-int encode+ 100 encode-int encode+ \ Merge size#1 my-address 20.0000 0 d+ my-space encode-phys encode+ \ Merge offset#2 0 encode-int encode+ 380 encode-int encode+ \ Merge size#2 " reg" property ---------------------------------------------------------------------

See also: property, "reg" in Chapter 5, "Properties".

repeat
( C: orig-sys dest-sys -- ) ( -- ) 13 -offset b2 bbranch -offset b(resolve)

Terminates a begin...while...repeat conditional loop. See while for more details.

reset-screen
( -- ) 01 58

reset-screen is one of the defer words of the display device interface. The terminal emulator package executes reset-screen when it has processed a character sequence that calls for resetting the display device to its initial state. reset-screen puts the display device into a state in which display output is visible (e.g. enable video).

This word is initially empty, but must be loaded with an appropriate routine in order for the terminal emulator to function correctly. This can be done with to, or it can be loaded automatically with fb1-install or fb8-install (which loads fb1-reset-screen or fb8-reset-screen, respectively). These words are NOPs, so it is very common to first call fbx-install and then to override the default setting for reset-screen with:

--------------------------------------
['] my-video-on to reset-screen --------------------------------------

See also: blink-screen

rl!
( quad qaddr -- ) 02 35

Stores a 32-bit word to a device register at qaddr with identical bit ordering as the input stack item. qaddr must be 32-bit aligned. Data is stored with a single access operation and flushes any intervening write buffers, so that the data reaches its final destination before the next FCode Function is executed.

For example:

----------------------------------
: my-reg! ( n -- ) my-reg rl! ; ----------------------------------
rl@
( qaddr -- quad ) 02 34

Fetches a 32-bit word from the device register at qaddr. qaddr must be 32-bit aligned. Data is read with a single access operation. The result has identical bit ordering as the original register data.

For example:

----------------------------------
: my-reg@ ( -- n ) my-reg rl@ ; ----------------------------------
roll
( xu ... x1 x0 u -- xu-1 ... x1 x0 xu ) 4F

Removes the u-th stack value, not including u itself, where the remaining stack items have indices beginning with 0. The u-th stack item is then placed on the top of the stack, moving the remaining items down one position. u must be between 0 and two less than the total number of elements on the stack (including u).

----------------------------------------------------------------
0 roll is a null operation 1 roll is equivalent to swap ( n1 n2 -- n2 n1 ) 2 roll is equivalent to rot ( n1 n2 n3 -- n2 n3 n1 ) 3 roll is equivalent to ( n1 n2 n3 n4 -- n2 n3 n4 n1 ) ----------------------------------------------------------------

For the sake of readability and performance, minimize your use of roll.

rot
( x1 x2 x3 -- x2 x3 x1 ) 4A

Rotates the top three stack entries, bringing the deepest to the top.

-rot
( x1 x2 x3 -- x3 x1 x2 ) 4B

Rotates the top three stack entries in the direction opposite from rot, putting the top number underneath the other two.

2rot
( x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2 ) 56

Rotates the top three pairs of numbers, bringing the third pair to the top of the stack.

rshift
( x1 u -- x2 ) 28

Shifts x1 right by u bit-places while zero-filling the high bits.

rw!
(w waddr -- ) 02 33

Stores a 16-bit word to a device register at waddr. waddr must be 16-bit aligned. Data is stored with a single access operation and flushes any intervening write buffers, so that the data reaches its final destination before the next FCode Function is executed.

The register is stored with identical bit ordering as the input stack item.

For example:

--------------------------------------
: my-count! ( w -- ) my-count rw! ; --------------------------------------
rw@
( w waddr -- ) 02 32

Fetches a 16-bit word from the device register at waddr. waddr must be 16-bit aligned. Data is read with a single access operation. The result has identical bit ordering as the original register data.

For example:

--------------------------------------
: my-count@ ( -- w ) my-count rw@ ; --------------------------------------
s"
( [text<"] -- text-str text-len ) none b(") len-byte xx-byte xx-byte ... xx-byte

Gather the immediately-following string delimited by " . Return the location of the string text-str text-len.

Since an implementation is only required to provide two temporary buffers, a program cannot depend on the system's ability to simultaneously maintain more than two distinct interpreted strings. Compiled strings do not have this limitation, since they are not stored in the temporary buffers.

s.
( n -- ) 47 2D 96 9A 49 98 97 90 A9 8F (.) type space

Displays the absolute value of n in a free-field format according to the current value of base. Displays a trailing space and, if n is negative, a leading minus sign. Even if the base is hexadecimal, n will be printed in signed format

See also: .

#s
( ud -- 0 0 ) C8

Converts the remaining digits in pictured numeric output.

.s
( ... -- ... ) 9F

Displays the contents of the data stack (using . ) according to base. The top of the stack appears on the right. The contents of the stack are unchanged.

For example:

--------------
ok 1 2 3 .s 1 2 3 ok . . . 3 2 1 --------------
sbus-intrcpu
( sbus-intr# -- cpu-intr# ) 01 31

Convert the SBus interrupt level (1-7) to the CPU interrupt level. The mapping performed will be system-dependent.

This word is included because of the possibility that, even on systems that nominally do not support SBus, SBus devices might be used via a bus-to-bus bridge.

screen-height
( -- height ) 01 63

A value, containing the total height of the display (in pixels). It can also be interpreted as the number of "lines" of memory.

screen-height is an internal value used by the fb1- and fb8- frame buffer support packages. In particular, this value is used in fbx-invert, fbx- erase-screen, fbx-blink-screen and in calculating window-top. fb1- install and fb8-install set it to the value of their height argument.

This function is included for historical compatibility. There is little reason for an FCode Program to use it. In fact, "standard" FCode Programs are forbidden from altering its value directly.

screen-width
( -- width ) 01 64

A value, containing the width of the display (in pixels). It can also be interpreted as the number of pixels (in memory) between one screen location and the next location immediately below it. The latter definition takes precedence if there is a conflict (e.g. there are unused/invisible memory locations at the end of each line).

screen-width is an internal value used by the fb1- and fb8- frame buffer support packages. fb1-install and fb8-install set it to their width argument.

This function is included for historical compatibility. There is little reason for an FCode Program to use it. In fact, "standard" FCode Programs are forbidden from altering its value directly.

set-args
( arg-str arg-len unit-str unit-len -- ) 02 3F

Sets the address and arguments of a new device node.

unit-string is a text string representation of a physical address in the address space of the parent device. set-args translates unit-string to the equivalent numerical representation by executing the parent instance's decode-unit method, and sets the current instance's probe-address (i.e. the values returned by my-address and my-space) to that numerical representation.

set-args then copies the string arg-string to instance-specific storage, and arranges for my-args to return the address and length of that copy when executed from the current instance.

set-args is typically used just after new-device. new-device creates and selects a new device node, and set-args sets its probe-address and arguments. Subsequently, the device node's properties and methods are created by interpreting an FCode Program with byte-load or by interpreting Forth source code.

The empty string is commonly used as the arguments for a new device node. For example:

-------------------
0 0 " 3" set-args -------------------
set-font
( addr width height advance min-char #glyphs -- ) 01 6B

This routine declares the font table to be used for printing characters on the screen. This routine must be called if you wish to use any of the fb1- or fb8- utility routines or >font.

Normally, set-font is called just after default-font. default-font leaves the exact set of parameters needed by set-font on the stack. This approach allows your FCode Program to inspect and/or alter the default parameters if desired. See default-font for more information on these parameters.

set-token
( xt immediate? fcode# -- ) DB

Assigns the FCode number fcode# to the FCode function whose execution token is xt, with compilation behavior specified by immediate? as follows:

sign
( n -- ) 98

If n is negative, appends an ASCII "-" (minus sign) to the pictured numeric output string. Typically used between <# and #'>. See (.) for a typical usage.

space
( -- ) A9 8F bl emit

Displays a single ASCII space character.

spaces
( cnt -- ) A5 2F A5 18 +offset A9 8F 15 -offset 0 max 0 ?do space loop

Displays cnt ASCII space characters. Nothing is displayed if cnt is zero.

span
( -- a-addr ) 88

A variable containing the count of characters actually received and stored by the last execution of expect.

For example:

------------------------------------------------------------------
h# 10 buffer: my-name-buff : hello ( -- ) ." Enter Your First name " my-name-buff h# 10 expect ." Sun Microsystems Welcomes " my-name-buff span @ type cr ; ------------------------------------------------------------------
start0
( -- ) F0

start0 may only be used as the first byte of an FCode Program. start0:

For portability, the preferred way to begin an FCode program in source form is with the fcode-version2 tokenizer macro. This macro causes the tokenizer to begin the FCode binary with the appropriate start byte and an FCode header.

See also: fcode-version2, start1, start2, start4, version1

start1
( -- ) F1

start1 may only be used as the first byte of an FCode Program. start1:

For portability, the preferred way to begin an FCode program in source form is with the fcode-version2 tokenizer macro. This macro causes the tokenizer to begin the FCode binary with the appropriate start byte and an FCode header.

See also: fcode-version2, start0, start2, start4, version1

start2
( -- ) F2

start2 may only be used as the first byte of an FCode Program. start2:

For portability, the preferred way to begin an FCode program in source form is with the fcode-version2 tokenizer macro. This macro causes the tokenizer to begin the FCode binary with the appropriate start byte and an FCode header.

See also: fcode-version2, start0, start1, start4, version1

start4
( -- ) F3

start4 may only be used as the first byte of an FCode Program. start4:

For portability, the preferred way to begin an FCode program in source form is with the fcode-version2 tokenizer macro. This macro causes the tokenizer to begin the FCode binary with the appropriate start byte and an FCode header.

See also: fcode-version2, start0, start1, start2, version1

state
( -- a-addr ) DC

A variable containing true if the system is in compilation state.

struct
( -- 0 ) a5 0

Initializes a struct...field structure by leaving a zero on the stack to define the initial offset. See field for details.

suspend-fcode
( -- ) 02 15

Tells the FCode interpreter that the device identification properties for the active package have been declared, and that the interpreter may postpone interpreting the remainder of the package if it so chooses.

If the FCode interpreter postpones (suspends) interpretation, it saves the state of the interpretation process so that interpretation can continue later. Attempts to open a suspended package cause the FCode interpreter to resume and complete the interpretation of that package before executing the package's open method.

For example:

-------------------------------------------------------
version1 " SUNW,my-name" namea " SUNW,my-model" encode-string " model" property suspend-fcode ... end0 -------------------------------------------------------

This feature is intended to save memory space and reduce the system start-up time by preventing the compilation of FCode drivers that are not actually used.

swap
( x1 x2 -- x2 x1 ) 49

Exchanges the top two stack items.

2swap
( x1 x2 x3 x4 -- x3 x4 x1 x2 ) 55

Exchanges the top two pairs of stack items.

then
( C: orig-sys -- ) ( -- ) b(resolve) b2

Terminates an if...then or an if...else...then conditional structure. See if for more details.

throw
( ... error-code -- ??? error-code | ... ) 02 18

Transfers control to the most recent dynamically enclosing error handling context, passing the indicated error code to that handler. error-code must be nonzero. If the value of error-code is zero, the zero is removed from the stack, but no other action is taken.

See catch for an example of use.

to
( param [old-name< ] -- ) none b(to) old-FCode#

Changes the contents of a value or a defer word:

-------------------------------------
number to name ( for a value ) xt to name ( for a defer word ) -------------------------------------
toggle-cursor
( -- ) 01 59

toggle-cursor is one of the defer words of the display device interface. The terminal emulator package executes toggle-cursor when it is about to process a character sequence that might involve screen drawing activity, and executes it again after it has finished processing that sequence. The first execution removes the cursor from the screen so that any screen drawing will not interfere with the cursor, and the second execution restores the cursor, possibly at a new position, after the drawing activity related to that character sequence is finished. toggle-cursor is also called once during the terminal emulator initialization sequence.

If the text cursor is on, toggle-cursor turns it off. If the text cursor is off, toggle-cursor turns it on. (On a bitmapped display, a typical implementation of this function inverts the pixels of the character cell to the right of the current cursor position.)

toggle-cursor is initially empty, but must be loaded with an appropriate routine in order for the terminal emulator to function correctly. This can be done with to, or it can be loaded automatically with fb1-install or fb8-install (which load fb1-toggle-cursor or fb8-toggle-cursor, respectively).

If the display device hardware has internal state (for example color map settings) that might have been changed by external software without firmware's knowledge, that hardware state should be re-established to the state that the firmware driver requires when the cursor is toggled to the "off" state (which indicates that firmware drawing operations are about to begin). This situation can occur, for example, when an operating system is using a display device, but that operating system uses firmware text output services from time to time, e.g. for critical warning messages.

See also: to, fb1-install, fb8-install

tokenizer[
( -- ) none

This is a tokenizer command that ends FCode byte generation and begins interpretation of the following text as tokenizer commands (up to the closing ]tokenizer). A tokenizer[...]tokenizer sequence may be used anywhere in an FCode Program, either in any definition or outside of definitions.

One plausible use for tokenizer[ would be to generate debugging text during the tokenizing process. (A cr flushes the text from the output buffer immediately, which is useful if the tokenizer crashes.) For example:

-----------------------------------------
... tokenizer[ .( step a) cr ]tokenizer ... tokenizer[ .( step b) cr ]tokenizer ... -----------------------------------------

emit-byte can be used with tokenizer[ to output a desired byte of FCode. This would be useful, for example, if you wished to generate a new FCode command that the tokenizer did not understand. For example:

----------------------------------------------------------
... tokenizer[ 1 emit-byte 27 emit-byte ]tokenizer \ manually output finish-device fcode ... ----------------------------------------------------------
]tokenizer
( -- ) none

Ends a tokenizer-only command sequence. See tokenizer[.

true
( -- true ) a4 -1

Leaves the value for the true flag (which is -1) on the stack.

tuck
( x1 x2 -- x2 x1 x2 ) 4C

Copies the top stack item underneath the second stack item.

type
( text-str text-len -- ) 90

A defer word that transfers text-len characters to the output beginning with the character at address text-str and continuing through text-len consecutive addresses. No action is taken if text-len is zero.

For example:

------------------------------------------------------------------
h# 10 buffer: my-name-buff : hello ( -- ) ." Enter Your First name " my-name-buff h# 10 expect ." Sun Microsystems Welcomes " my-name-buff span @ type cr ; ------------------------------------------------------------------

The output will go either to a frame buffer or to a serial port depending on which is enabled.

u#
( u1 -- u2 ) 99

The remainder of u1 divided by the value of base is converted to an ASCII character and appended to the output string with hold. u2 is the quotient and is maintained for further processing. Typically used between <# and #'>.

u#'>
( u -- str len ) 97

Pictured numeric output conversion is ended dropping u. str is the address of the resulting output array. len is the number of characters in the output array. str and len together are suitable for type. See (.) and (u.) for typical usages.

u#s
( u1 -- u2 ) 9A

u1 is converted, appending each resultant character into the pictured numeric output string until the quotient is zero (see: #). A single zero is added to the output string if u1 was initially zero. Typically used between <# and #'>. See (.) and (u.) for typical usages.

This word is equivalent to calling # repeatedly until the number remaining is zero.

u.
( u -- ) 9B

Displays u as an unsigned number in a free-field format according to the value in base. A trailing space is also displayed.

For example:

---------------
ok hex -1 u. ffffffff ---------------
u<
( u1 u2 -- unsigned-less? ) 40

Returns true if u1 is less than u2 where u1 and u2 are treated as unsigned integers.

u<=
( u1 u2 -- unsigned-less-or-equal? ) 3F

Returns true if u1 is less than or equal to u2 where u1 and u2 are treated as unsigned integers.

u'>
( u1 u2 -- unsigned-greater? ) 3E

Returns true if u1 is greater than u2 where u1 and u2 are treated as unsigned integers.

u=
( u1 u2 -- unsigned-greater-or-equal? ) 41

Returns true if u1 is greater than or equal to u2 where u1 and u2 are treated as unsigned integers.

(u.)
( u -- addr len ) 96 9a 97 <# u#s u#'>

This is a numeric conversion primitive used to implement display words such as u. . It converts an unsigned number into a string according to the value in base.

For example:

--------------------------
ok hex d# -12 (u.) type fffffff4 --------------------------
u2/
( x1 -- x2 ) 58

x2 is the result of x1 logically shifted right one bit. A zero is shifted into the vacated sign bit.

For example:

---------------
ok -2 u2/ .s 7fffffff ---------------
um*
( u1 u2 -- ud.prod ) D4

Multiplies two unsigned 32-bit numbers yielding an unsigned 64-bit product.

For example:

------------------------
ok hex 3 3 u*x .s 9 0 ok 4 ffff.ffff u*x .s fffffffc 3 ------------------------
um/mod
( ud u -- urem uquot ) D5

Divides an unsigned 64-bit number by an unsigned 32-bit number yielding an unsigned 32-bit remainder and quotient

u/mod
( u1 u2 -- urem uquot ) 2B

rem is the remainder and quot is the quotient after dividing u1 by u2. All values and arithmetic are unsigned. All values are 32-bit.

For example:

-------------------
ok -1 5 u/mod .s 0 33333333 -------------------
unloop
( -- ) ( R: sys -- ) 89

Discards loop control parameters.

until
( C: dest-sys -- ) ( done? -- ) 14 -offset b?branch -offset

Marks the end of a begin...until conditional loop. When until is encountered, done? is removed and tested. If done? is true, the loop is terminated and execution continues just after the until. If done? is false, execution jumps back to just after the corresponding begin.

For example:

-----------------------------------------------------
: probe-loop ( addr -- ) \ generate a tight 'scope loop until a key is pressed. begin dup l@ drop key? until drop ; -----------------------------------------------------
upc
( char1 -- char2 ) 81

char2 is the upper case version of char1. If char1 is not a lower case letter, it is left unchanged.

For example:

--------------------------------------------------
: continue? ( -- continue? ) ." Want to Continue? Enter Y/N" key dup emit upc ascii Y = ; --------------------------------------------------

See also: lcc

u.r
( u size -- ) 9C

u is converted according to the value of base and then displayed as an unsigned number right-aligned in a field size digits wide. A trailing space is not displayed.

If the number of digits required to display u is greater than size, all the digits are displayed with no leading spaces in a field as wide as necessary.

For example:

-----------------------------------------
: formatted-output ( -- ) my-base h# 8 u.r ." base" cr my-offset h# 8 u.r ." offset" cr ; -----------------------------------------
user-abort
( ... -- ) ( R: ... -- ) 219

Used in an alarm routine to signify that the user has typed an abort sequence. When alarm finishes, instead of returning to the program that was interrupted by the execution of alarm, it enters the OpenBoot command interpreter by calling abort.

For example:

------------------------------------------------------------------
: test-dev-status ( -- error? ) ... ; : my-checker ( -- ) test-dev-status if user-abort then ; : install-abort ( -- ) ['] my-checker d# 10 alarm ; ------------------------------------------------------------------
value
(E: -- x ) ( x "new-name< " -- ) (header) b8 new-token|named-token|external-token b(value)

Creates and initializes a value with the name new-name. When later executed, new-name leaves its value on the stack. The value of new-name can be changed with to.

For example:

--------------------------
ok 123 value foo foo . 123 ok 456 to foo foo . 456 --------------------------

In FCode Source, value cannot appear inside a colon definition.

variable
(E: -- a-addr ) ( "new-name< " -- ) (header) b9 new-token|named-token|external-token b(variable)

Creates an uninitialized variable named new-name. When later executed, new-name leaves its address on the stack. The alignment of the returned address is system-dependent. The address holds a 32-bit value.

The value of new-name can be changed with ! and fetched with @ .

For example:

--------------------------------------
ok variable foo 123 foo ! foo @ . 123 ok 456 foo ! foo ? 456 --------------------------------------

In FCode Source, value cannot appear inside a colon definition.

version1
( -- ) FD

version1 may only be used as the first byte of an FCode Program. version1:

For portability, the preferred way to begin an FCode program in source form is with the fcode-version1 tokenizer macro. This macro causes the tokenizer to begin the FCode binary with the version1 byte and an FCode header.

See also: fcode-version2, start0, start1, start2, start4

Firmworkers, please excuse the format inconsistency. Since I will be reformatting this chapter to conform to the format in the next section, I am leaving it as is.
versionx?
( -- flag ) code# ??

A group of tokenizer macros to determine the FCode version of the system running the FCode interpreter. They include:

------------------------------------------
Word Generates ------------------------------------------
             
version1?    version b(lit) 2000.0000 <
             
version2?    version b(lit) 2000.0000 =
             version b(lit) 3000.0000 <
             
version2.0?  version b(lit) 2000.0000 =
             
version2.1?  version b(lit) 2000.0001 =
             
version2.2?  version b(lit) 2000.0002 =
             
version2.3?  version b(lit) 2000.0003 =

------------------------------------------

Each returns true if the named version matches the system running the FCode interpreter.

w!
( n adr -- ) code# 74

The low-order 16-bits of n are stored at location adr (through adr+1 ). The higher byte is stored at adr ; the lower byte is stored at adr+1 . adr must be on a 16-bit boundary; it must be evenly divisible by 2.

w,
( n -- ) code# d1

Compile two bytes into the dictionary. The dictionary pointer must be two- byte-aligned.

See c, for limitations.

w@
( adr -- n ) code# 6f

Fetch the 16-bit number stored at adr (through adr+1 ). The higher byte is at adr ; the lower byte is at adr+1 . The remaining high bytes of n are set to zero. adr must be on a 16-bit boundary; it must be evenly divisible by 2.

/w
( -- n ) code# 5b

n is the size in bytes of a 16-bit word: 2.

/w*
( nu1 -- nu2 ) 67

nu2 is the result of multiplying nu1 by /w. This is the portable way to convert an index into a byte offset.

<w@
( waddr -- n ) 70

Fetches the 16-bit number stored at waddr and extends its sign into the upper bytes. waddr must be 16-bit-aligned.

For example:

-------------------------------
ok 9123 8000 w! 8000 <w@ .h ffff9123 ok 8000 w@ .h 9123 -------------------------------
wa+
( addr1 index -- addr2 ) 5F

Increments addr1 by index times the value of /w. This is the portable way to increment an address.

wa1+
( addr1 -- addr2 ) 63

Increments addr1 by the value of /w. This is the portable way to increment an address.

wbflip
( w1 -- w2 ) 80

w2 is the result of exchanging the two low-order bytes of the number w1. The two upper bytes of w1 must be zero, or erroneous results will occur.

wbflips
( waddr len -- ) 02 36

Swaps the order of the bytes in each 16-bit word in the memory buffer waddr len.

waddr must be 16-bit-aligned. len must be a multiple /w.

wbsplit
( w -- b1.lo b2.hi ) AF

Splits the two lower bytes of w into two separate bytes (stored as the lower byte of each resulting item on the stack). The upper bytes of w must be zero.

while
( C: dest-sys -- orig-sys dest-sys ) ( continue? -- ) 14 +offset b?branch +offset

Tests the exit condition for a begin...while...repeat conditional loop. When the while is encountered, continue? is removed from the stack and tested. If continue? is true, execution continues from just after the while through to the repeat which then jumps back to just after the begin. If continue? is false, the loop is exited by causing execution to jump ahead to just after the repeat.

For example:

-----------------------------------------------------
: probe-loop ( addr -- ) \ generate a tight 'scope loop until a key is pressed. begin key? 0= while dup l@ drop repeat drop ; -----------------------------------------------------
window-left
( -- border-width ) 01 66

A value, containing the offset (in pixels) of the left edge of the active text area from the left edge of the visible display. The "active text area" is where characters are actually printed. (There is generally a border of unused blank area surrounding it on all sides.) window-left contains the size of the left portion of the unused border.

The size of the right portion of the unused border is determined by the difference between screen-width and the sum of window-left plus the width of the active text area (#columns times char-width).

This word is initially set to 0, but should always be set explicitly to an appropriate value if you wish to use any fb1- or fb8- utility routines. This can be done with to, or it can be set automatically by calling fb1-install or fb8-install.

When set with fbx-install, a calculation is done to set window-left so that the available unused border area is evenly split between the left border and the right border. (The calculated value for window-left is rounded down to the nearest multiple of 32, though. This allows all pixel-drawing to proceed more efficiently.) If you wish to use fbx-install but desire a different value for window-left, simply change it with to after calling fbx-install.

window-top
( -- border-height ) 01 65

A value, containing the offset (in pixels) of the top of the active text area from the top of the visible display. The "active text area" is where characters are actually printed. (There is generally a border of unused blank area surrounding it on all sides.) window-top contains the size of the top portion of the unused border.

The size of the bottom portion of the unused border is determined by the difference between screen-height and the sum of window-top plus the height of the active text area (#lines times char-height).

This word is initially set to 0, but should always be set explicitly to an appropriate value if you wish to use any fb1- or fb8- utility routines. This can be done with to, or it can be set automatically by calling fb1-install or fb8-install. When set with fbx-install, a calculation is done to set window-top so that the available unused border area is evenly split between the top border and the bottom border. If you wish to use fbx-install but desire a different value for window-top, simply change it with to after calling fbx-install.

within
( n min max -- min<=n<max? ) 45

min<=n<max? is true if n is between min and max, inclusive of min and exclusive of max.

See also: between

wljoin
( w.lo w.hi -- quad ) 7D

Merges two 16-bit numbers into a 32-bit number. The high bytes of w.lo and w.hi must be zero.

wpeek
( waddr -- false | w true ) 221

Tries to read the 16-bit word at address waddr. Returns w and true if the access was successful. A false return indicates that a read access error occurred. waddr must be 16-bit aligned.

wpoke
( w waddr -- okay? ) 224

Tries to write the 16-bit word at address waddr. Returns true if the access was successful. A false return indicates that a write access error occurred. waddr must be 16-bit aligned.

Note: wpoke may be unreliable on bus adapters that buffer write accesses.

xor
( x1 x2 -- x3 ) 25

x3 is the bit-by-bit exclusive-or of x1 with x2.