This dictionary describes the pre-defined FCode words that you can use as part of FCode source code programs. Appendix A, "FCode Reference", contains a command summary, with words grouped by function.
The words are given 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.
All arithmetic uses 32-bit signed values, unless otherwise specified.
Defining words create a header by calling external-token, named-token, or new-token. See these words for more details.
All FCode byte values listed in this chapter are given in hexadecimal. Version 2 FCodes cannot be used OpenBoot 1 systems, they are called out in the dictionary definitions by "Version 2".
The rest of this chapter contains definitions of the FCodes and tokenizer macros defined for use in the SPARCstation OpenBoot PROM.
Store n at adr. For more portable code, use l! if you explicitly want a 32-bit access. adr must be aligned as given by variable.
This word is used to compile a text string, delimited by a " . At execution time, the address and length of the string is left on the stack. For example:
--------------------------------------------------
" SUNW,new-model" xdrstring " model" attribute --------------------------------------------------
You can embed control characters and 8-bit binary numbers within 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 escapes:
Table 11-1 Escape Sequences in Text Strings
---------------------------------------------------------------------------
Syntax Function ---------------------------------------------------------------------------
"" quote (") "n newline "r carret "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 ---------------------------------------------------------------------------
"<whitespace'> terminates the string, as usual.
" followed by any other printable character not mentioned above is equivalent to that character. This syntax is completely backwards compatible with old code, since the only legal previous usage was "<whitespace'>
For example:
------------------------------------------------------------------------------
" This is "(01 32 8e)abc"nA test xyzzy "!"! abcdefg""hijk"^bl" ^^^^^^ ^ ^ ^ ^ ^ 3 bytes newline 2 bells " control b ------------------------------------------------------------------------------
The "(hh hh hh hh) form is useful for entering binary data.
Any non-hex characters (such as space or comma) are ignored within the data field of "( ...), and thus make useful delimiters. The "makearray" tool can be used in conjunction with this syntax to easily incorporate large binary data fields into any FCode program.
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, current implementations permit only two interpreted strings to be active at any given time, a third interpreted string overwrites the first one. This limitation does not apply in colon definitions.
The remainder of +L1 divided by the value of base is converted to an ASCII character and appended to the output string toward lower memory addresses. +L2 is the quotient and is maintained for further processing. Typically used between <# and #'>.
Pictured numeric output conversion is ended dropping L. adr is the address of the resulting output array. +n is the number of characters in the output array. adr and +n together are suitable for type. See (.) and (u.) for typical usages.
Used to generate the code field address (acf) of the word immediately following the ' . ' should only be used outside of definitions. See ['] for more details.
For example:
-------------------------------------------
defer opt-word ( -- ) ' noop is opt-word -------------------------------------------
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. See also (s .
For example:
---------------------------------------
: 4drop ( a b c d -- ) 2drop ( a b ) 2drop ( ) ; ---------------------------------------
This is the numeric conversion primitive, used to implement display words such as "." It converts a number into a string. If n is negative, the first character in the array will be a minus (-) sign.
For example:
----------------------------------------------------------------------
: show-version ( -- ) ." CPU bootprom version is " base @ d# 16 base ! ( old-base ) firmware-version ( old-base version ) lwsplit (.) type ascii . emit .h cr base ! ( ) ; ----------------------------------------------------------------------
n3 is the arithmetic product of n1 times n2. If the result cannot be represented in one stack entry, the least significant bits are kept.
Calculates n1*n2/n3. The inputs, outputs and intermediate products are all 32-bit.
n3 is the arithmetic sum of n1 plus n2.
n is added to the value stored at adr. This sum replaces the original value at adr. adr must be aligned as given by variable.
Compile a number into the dictionary. In current systems, the number of bytes compiled is 4 (same as l,). See c, for limitations. The dictionary pointer must be two-byte aligned.
For example, to create an array containing integers 40004000 23 45 6734:
------------------------------------------------
create my-array 40004000 , 23 , 45 , 6734 , ------------------------------------------------
n3 is the result of subtracting n1 minus n2.
Leave 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.
The absolute value of n is displayed in a free field format with a leading minus sign if n 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. .
This word compiles a text string, delimited by " . At execution time, the string is displayed, for example, in ." hello world"
This word is equivalent to using " text" type
." is normally used only within 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 .( to print anything while the FCode PROM is being interpreted.
See tokenizer[ for details about printing at tokenize time.
Gathers a text string, delimited by ) , to be immediately displayed during probe time. For example:
------------------
.( hello world) ------------------
This word is equivalent to: " text" type
Use this to print out text at the time the FCode PROM is being interpreted (you may wish to follow it with a cr to flush out the text buffer immediately). This word may be called either inside or outside of definitions; the text is immediately displayed in either case.
Note that the string will typically be printed out of serial port A, since any framebuffer present may not yet be activated at the time that SBus slots are being probed. Use ." for any printing to be done when new words are later executed.
See tokenizer[ for details about printing at tokenize time.
Calculates n1 divided by n2. An error condition results if the divisor (n2) is zero. See /mod.
Leave 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.
Flag is true if n is less than zero (negative).
Flag is true if n is less than or equal to zero.
Flag is true if n is zero. This word will invert any flag.
Flag is true if n is not zero.
Flag is true if n is greater than zero.
Flag is true if n is greater than or equal to zero.
Leave 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.
n2 is the result of adding one to n1.
n2 is the result of subtracting one from n1.
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.
n1 and n2 are stored in consecutive 32-bit locations starting at adr. n2 is stored at the lower address.
n2 is the result of shifting n1 left one bit. A zero is shifted into the vacated bit position. This is equivalent to multiplying by 2.
n2 is the result of adding 2 to n1.
n2 is the result of subtracting 2 from n1.
n2 is the result of arithmetically shifting n1 right one bit. The sign is included in the shift and remains unchanged. This is equivalent to dividing by 2.
n1 and n2 are two numbers stored in consecutive 32-bit locations starting at adr. n2 is the number that was stored at the lower address.
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.
Begin a new definition, terminated by ; Used in the form:
-------------------------
: newname ... ; -------------------------
Later usage of 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.
Ends the compilation of a colon definition. See also : .
Flag is true if n1 is less than n2. n1 and n2 are signed integers.
Initialize pictured numeric output conversion. You can use the words:
----------------------------
<# # #s hold sign #'> ----------------------------
to specify the conversion of a 32-bit number into an ASCII character string stored in right-to-left order. See (.) and (u.) for typical usages.
n2 is the result of logically left shifting n1 by +n places. Zeroes are shifted into the least-significant bits.
For example:
-------------------------------------------------------------------
: bljoin ( byte.low byte.lowmid byte.highmid byte.high -- L ) 8 << + 8 << + 8 << + ; -------------------------------------------------------------------
Flag is true if n1 is less than or equal to n2. n1 and n2 are signed integers.
Flag is true if n1 is not equal to n2. n1 and n2 are signed integers.
Flag is true if n1 is equal to n2. n1 and n2 are signed integers.
Flag is true if n1 is greater than n2. n1 and n2 are signed integers.
Flag is true if n1 is greater than or equal to n2. n1 and n2 are signed integers.
n2 is the result of logically right shifting n1 by +n 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 ; ----------------------------------
Fetch and print the 32-bit value at the given address. An old standard Forth word, primarily used interactively.
n is the value stored at adr. For more portable code, use l@ if you explicitly want a 32-bit access. adr must be aligned as given by variable.
' or ['] are used to generate the code field address (acf) 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 within definitions for the creation of language extensions, but such usage is not applicable to FCode programs.
Ignore the rest of the input line after the \ . It can occur anywhere on an input line. Note that a space must be present after the \ . See ( or (s for another form for delimiting comments.
For example:
--------------------------------------------------
0 value his-ihandle \ place to save someone's ihandle --------------------------------------------------
Arithmetic left-shift (left-shift with sign-extend), to round out the existing words <<, >'>, and >a . This word is useless, because the carry out from an arithmetic left shift is not accessible later.
n2 is the result of arithmetically right shifting n1 by +n places. The sign bit of n1 is shifted into the most-significant bits.
For example:
----------------------
ffff.0000 6 >a .h ----------------------
shows: fffffc00 , while
-------------------
ffff.0000 6 > .h -------------------
shows: 3fffc00 .
Aborts program execution. Control returns to ok prompt. Called after encountering fatal errors.
For example:
---------------------------------------------------------
: probe-loop ( adr -- ) \ generate a tight probe loop until any key is pressed. begin dup l@ drop key? if abort then again ; ---------------------------------------------------------
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).
Used in the form begin ... again to generate an infinite loop. Use Stop-A from the keyboard, or abort or exit, to exit from this loop. Use this word with caution!
For example:
---------------------------------------------------------
: probe-loop ( adr -- ) \ generate a tight probe loop until any key is pressed. begin dup l@ drop key? if abort then again ; ---------------------------------------------------------
Arranges to periodically execute the package method acf at intervals of n milliseconds (to the best accuracy possible).
acf is the compilation address, as returned by [']. Each time the method is
called, the current instance will be the same as the current instance at the time
that alarm
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 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 the new word causes the assigned FCode value of the old word to be generated. One implication is that the new word will not appear in the OpenBoot dictionary after the FCode program is compiled.
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-attr get-package-attribute --------------------------------------
Increase adr1 to the next machine word boundary - to the next value evenly divisible by 4. The correct boundary could vary on other CPU implementations.
Allocate some free physical memory from Forth, and return its virtual address. See free-mem.
For example:
----------------------------------------------
h# 100 alloc-mem ( virt ) constant my-buff ----------------------------------------------
n3 is the bit-by-bit logical and of n1 with n2.
Interpret the next letter as an ASCII code. For example:
-------------------------
ascii C (equals hex 43) ascii c (equals hex 63) -------------------------
attribute is the way to pass properties from an FCode program to a SunOS device driver. A property consists of two strings: a name string and a value string. The name string gives the name of the property, and the value string gives the value associated with that name. For example, a framebuffer may wish to declare a property named "hres" (for horizontal resolution) with a value of 1152.
The attribute command requires two strings on the stack - the value string 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 attribute name is stored only after converting uppercase letters, if any, to lower case. For example:
-------------------------------------------------
" A21-b" xdrstring " New_verSION" attribute -------------------------------------------------
is stored as if entered
---------------------------------------------
" A21-b" xdrstring " new_version" attribute ---------------------------------------------
The value string, however, must be in the xdr format. See Chapter 5, "Properties" for more information on creating xdr-format strings.
All properties created by an FCode program are stored in a "device tree" by OpenBoot. This tree may then be queried by a SunOS device driver, using getprop or getlongprop.
The FCode program and the SunOS device driver may agree on any arbitrary set of names and values to be passed, with virtually no restrictions. Several names, though, have special meaning. For many of them, a shorthand command also exists that makes the attribute declaration a bit simpler.
For example:
------------------------------------------------
" SUNW,new-model" xdrstring " model" attribute ------------------------------------------------
See also: name, reg, intr, model and Chapter 5, "Properties" for more information.
Interpret the next number in binary (base 2), regardless of any previous settings of hex, decimal, binary or octal. Only the immediately-following number is affected, the current numeric base setting is unchanged. For example:
--------------------------------
hex b# 100 (equals decimal 4) 100 (equals decimal 256) --------------------------------
See also d#, h#, and o#.
An internal word, generated by words such as " or ." to leave a text string on the stack. The FCode for b(") should always be followed by an 8-bit length, then by the appropriate number of bytes representing the desired test string. Never use the word b(") in source code.
An internal word, generated by ' or ['] to leave on the stack the code field address of the immediately following word. The FCode for b(') should always be followed by the FCode of the desired word. Never use the word b(') in source code.
An internal word, generated by +loop . The FCode for b(+loop) should always be followed by a negative offset (either 8-bit or 16-bit, see offset16). Never use the word b(+loop) in source code.
An internal word, generated by the defining word : . This is the type entry for : needed by named-token or new-token . See these words for more details. Never use the word b(:) in source code.
An internal word, generated by ; to end a colon definition. Never use the word b(;) in source code.
An internal word, generated by begin . Never use the word b(<mark) in source code.
An internal word, generated by repeat, else, and then . Never use the word b(resolve) in source code.
An internal word, generated by ?do . The FCode for b(?do) should always be followed by a positive offset (either 8-bit or 16-bit, see offset16). Never use the word b(?do) in source code.
An internal word, generated by the defining word buffer: . This is the type entry for buffer: needed by external-token, named-token, or new- token . See these words for more details. Never use the word b(buffer:) in source code.
An internal word, generated by case . Never use the word b(case) in source code.
An internal word, generated by the defining word constant . This is the type entry for constant needed by external-token, named-token or new- token . See these words for more details. Never use the word b(constant) in source code.
An internal word, generated by the defining word create. This is the type entry for create needed by external-token, named-token or new-token . See these words for more details. Never use the word b(create) in source code.
An internal word, generated by the defining word defer . This is the type entry for defer needed by external-token, named-token or new-token . See these words for more details. Never use the word b(defer) in source code.
An internal word, generated by do . The FCode for b(do) should always be followed by a positive offset (either 8-bit or 16-bit, see offset16). Never use the word b(do) in source code.
An internal word, generated by endcase . Never use the word b(endcase) in source code.
An internal word, generated by endof . Never use the word b(endof) in source code.
An internal word, generated by the defining word field . This is the type entry for field needed by external-token, named-token or new-token . See these words for more details. Never use the word b(field) in source code.
An internal word, generated by is .
Never use the word b(is) in source code.
An internal word, generated by leave .
Never use the word b(leave) in source code.
Any input number, such as 205 or -14, will create the b(lit) FCode (code#10), followed by 32-bits (4 bytes) with the actual binary value in two's-complement arithmetic. The number base (hex, decimal or any other chosen radix) is controlled by any previous uses of the tokenizer directives hex, decimal, and so on, or by numeric input control words such as h#, d#, ascii, and so on. Thus,
----------------
decimal ... 20 ----------------
would be encoded as the hex bytes 10 00 00 00 14
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.
Never use the word b(lit) in source code.
An internal word, generated by loop . The FCode for b(loop) should always be followed by a negative offset (either 8-bit or 16-bit, see offset16).
Never use the word b(loop) in source code.
An internal word, generated by of . The FCode for b(of) should always be followed by a positive offset (either 8-bit or 16-bit, see offset16). Never use the word b(of) in source code.
An internal word, generated by the defining word value . This is the type entry for value needed by external-token, named-token or new-token . See these words for more details. Never use the word b(value) in source code.
An internal word, generated by the defining word variable . This is the type entry for variable needed by external-token, named-token or new- token . See these words for more details. Never use the word b(variable) in source code.
An internal word, generated by until, while, and if . The FCode for b?branch should always be followed by an offset (either 8-bit or 16-bit, see offset16). Never use the word b?branch in source code.
The address of a variable containing 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. For example, to print the current value of base, use:
-----------
base @ .d -----------
The tokenizer words binary, decimal, hex, or octal are also available for changing the value in base as desired. However, these four words behave differently depending whether they occur within a definition or outside of a definition.
If any of binary, decimal, hex, or octal occur within a definition, then they will be compiled, later causing a change to the value in base when that definition is executed.
If any of binary, decimal, hex, or octal occur outside of a definition, however, then they are interpreted as commands 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 Toolkit itself, which can create much confusion for any user (the default value for base is hexadecimal). If you must change the base, Sun recommends that you save and then restore the original base, as in:
--------------------------------
: .o ( n -- ) \ Print n in octal base @ swap ( oldbase n ) octal . ( 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 binary, decimal, hex, octal, b#, d#, h#, and o#, but these words only affect the tokenizer input base; they but do not affect the value in base. For example:
-------------------------------------------------------------------------------------------
(assume initial value in base is 16, i.e. Toolkit is in hex) (no assumptions should be made about the initial tokenizer base) fcode-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 ( -- ) octal (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-version1, and make liberal use of b#, d#, o#, h#,.h and.d.
Bad: changing base either directly or by calling binary, decimal, hex, or octal from within a definition.
An internal word, generated by again, repeat, and else . The FCode for bbranch should always be followed by an offset (either 8-bit or 16-bit,see offset16). Never use the word bbranch in source code.
Marks the beginning of a conditional loop, such as begin ... until , begin ... while ... repeat , or begin ... again . See these other words for more details.
n is the ASCII code for the bell character; decimal 7.
flag is true if n is between min and max, inclusive of both endpoints (min <= n <= max). See within for a different form of comparison.
If outside of a definition, commands the tokenizer program to interpret subsequent numbers in binary (base 2). If within a definition, change the value in base affecting later numeric output when the FCode program is executed. See base.
The ASCII code for the space character; decimal 32, hex 20.
len bytes of memory beginning at adr are set to the ASCII character value for space (hex 20). No action is taken if len is zero.
A defer word, called by the terminal emulator when needed to flash the entire screen.
This word is initially empty, but must be loaded with an appropriate routine in order for the terminal emulator to function correctly.
This may be done with is, or it may 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 is 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.
Merge four bytes into a single 32-bit word. Incorrect results may be generated unless the high 24 bits of each stack item are zero.
Convert the parameter field address of a word to its code field address.
Convert the code field address of a word to its parameter field address.
Convert 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 -----------------------
n is the ASCII code for the backspace character; decimal 8.
Allocate some memory and create a name that, when executed, leaves on the stack the virtual address of the desired memory. Create with:
------------------
200 buffer: name ------------------
Merge two bytes into the low 16-bits of a stack entry (the upper bits are zero). Incorrect results may be generated unless the high 24 bits of each stack item are zero.
This byte (at location 0) followed by 3 more identifier bytes, was used during some of the early OpenBoot development as a replacement for actual FCode, by providing a single "magic" number to identify an SBus device. It was a temporary measure only, as it required the boot PROM to "know" the correct magic number for a given device.
This feature is no longer supported, and should not be used under any circumstances.
The least significant 8 bits of n are stored in the byte at adr .
Compile a byte into the dictionary. This word may 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.
The byte at address adr is placed into the low 8-bits of n (the upper bits are padded with zeroes).
n is the size in bytes of a byte, which is 1. See /w, /l, and /n.
n2 is the result of multiplying n1 by the length in bytes of a byte. This is useful for converting an index into a byte offset.
adr2 is the address of the index'th character after adr1 . ca+ should be used in preference to + when calculating addresses because it more clearly expresses the intent of the operation and is more portable.
adr2 is the address of the next byte after adr1 . ca1+ should be used in preference to 1+ because it more clearly expresses the intent of the operation and is more portable.
Executes the device interface method adr len within the open package instance ihandle . The ellipses (...) indicate that the contents of the stack before and after the method is called depend upon the particular method being called.
For example:
--------------------------------------------------------------------------
: dma-alloc ( #bytes -- vadr ) " dma-alloc" my-parent $call-method ; --------------------------------------------------------------------------
See open-package.
Executes the device interface method acf within the open package instance ihandle. See find-method and open-package. The ellipses (...) indicate that the contents of the stack before and after the method is called depend upon 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 acf of found method : init ( -- ) my-args " disk-label" $open-package ( ihandle ) is label-ihandle " offset" label-ihandle ihandlephandle ( name-adr name-len phandle ) find-method if is offset-method else ." Can't find offset method " then ; init : add-offset ( d.byte# -- d.bytes# ) offset-method label-ihandle call-package ; ------------------------------------------------------------------
Calls the method named by adr len within the parent instance. If the called package has no such method, an error is signaled with throw. Equivalent to:
--------------------------
my-parent $call-method --------------------------
The ellipses (...) indicate that the contents of the stack before and after the method is called depend upon the particular method being called.
For example:
-------------------------------------------------------------------
: my-dma-alloc ( -- vadr ) h# 2000 " dma-alloc" $call-parent ; -------------------------------------------------------------------
n is the ASCII code for the carriage return character; decimal 13, hex 0d.
A case statement is started that selects its action based on the value of selector. 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 ; ----------------------------------------------------
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 just before the encase). 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.
case statements can only be used within colon definitions.
Creates a new error handling context and executes acf in that context.
If a throw (see below) is called during the execution of acf,
If throw is not called during the execution of acf, the error handling context is removed and catch returns a false. The stack effect is otherwise the same as if acf 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 -----------------------------
An important thing to note is that upon a non-zero throw, only the stack depth is guaranteed to be the same as before catch, not the data stack contents.
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 may be done with is, but is normally done by calling set-font .
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 may be done with is, but is normally done by calling set-font .
The fb1 and fb8 character painting support routines in current PROMs do not support widths larger than 16 (decimal). However, it is possible to display wider characters by splitting each character bitmap into 2 halves and calling fbx-draw-character twice.
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 ; -----------------------------------------------------
Closes the 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 ; ---------------------------------------------------
Copy len bytes of an array starting at adr1 to adr2 . This word calls move, which is "smart" and correctly handles overlapping arrays in either direction.
cmove and cmove'> are older standard Forth words that explicitly command in which order to copy the bytes (back-to-front, or front-to-back). In most cases, the distinction is not important. This distinction is important if the arrays overlap, else the source array may be overwritten prematurely, with unexpected results.
move will also perform 16-bit, 32-bit or possibly even 64-bit operations (for better performance) if the alignment of the operands permit. If your hardware requires explicit 8-bit or 16-bit accesses, you will probably wish to use an explicitly-coded do... loop instead.
Copy len bytes of an array starting at adr1 to adr2 . This word simply calls move . See cmove for more information.
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 (this is not the leftmost pixel of the framebuffer - see window- left ).
This word can (and should) be looked at as needed if your FCode program is implementing its own set of framebuffer primitives.
For example:
------------------------------------------
: set-column ( column# -- ) 0 max #columns 1- min is column# ; ------------------------------------------
This is a value that returns the number of columns of text, i.e. the number of characters in a line, to be displayed using the boot PROM's terminal emulator. It must be set to a proper value in order for the terminal emulator to function correctly.
#columns is defined in the boot PROM with an initial value of 80 (decimal), but it should always be actively set by the FCode program. This may be done with is, or it may be handled automatically as one of the functions performed by fb1-install or fb8-install . The value set by fbx-install or is the smaller of the passed #cols parameter and the screen-#columns NVRAM parameter.
For example:
------------------------------------------
: set-column ( column# -- ) 0 max #columns 1- min is column# ; ------------------------------------------
Compare two byte arrays starting at addresses adr1 and adr2 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 adr1 is numerically greater than the corresponding character in the array at adr2 . n is -1 if the first differing character in the array at adr1 is numerically less than the corresponding character in the array at adr2 .
For example:
-----------------------------------
" this" drop " that" comp .h -----------------------------------
shows 1
---------------------------------------
" thisismy" drop " this" comp .h ---------------------------------------
shows 0
-----------------------------------
" thin" drop " this" comp .h -----------------------------------
shows ffffffff .
Creates a named constant. The name is initially created with:
---------------------
456 constant purple ---------------------
where the number before constant is the desired value for purple . Later occurrences of purple will leave the correct value on the stack. constant values should never be changed by the program. If you wish to change the value of a constant by the program, you should declare it to be a value instead.
Interpret the next letter as a control-code. For example:
--------------------------
control c ( equals 03 ) --------------------------
Convert 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 "adr len" format.
For example:
---------------------------------------------------------
h# 100 alloc-mem constant my-buff " This is a string" my-buff pack ( pstr ) count type ---------------------------------------------------------
Tries to read the 8-bit byte at address adr. Returns the data and true if the access was successful. A false return indicates that a read access error occurred.
Attempts to write the 8-bit byte at address adr. Returns true
Note - cpoke may be unreliable on bus adapters that buffer write accesses.
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 ; ----------------------------------------------
Output only the carriage return character (carret, hex 0d). This word is not commonly used; see cr .
Create a name. It returns the address of memory at run time, immediately following the name in the dictionary. You can use this word to create 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.
In the current implementation, create may not be used within definitions in an FCode program. The common Forth construct create...does is not supported.
n is displayed in decimal (using . ). The value of base is not permanently affected.
Interpret the next number in decimal (base 10), regardless of any previous settings of hex, decimal, binary, 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 b#, h#, and o#.
If outside of a definition, commands the tokenizer program to interpret subsequent numbers in decimal (base 10). If within a definition, change the value in base affecting later numeric output when the FCode program is executed. See base .
Converts a string into a physical address and space.
For example:
-----------------------------------
" 4,ff001200" decode-2int .s will show: ff001200 4 " 4" decode-2int .s will show: 0 4 -----------------------------------
This function returns all 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:
fontbase - 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.
Create a defer'd executable. This is a word that has a variable behavior, depending on the function that is later loaded into it. The name is initially created with:
-------------
defer blob -------------
Later, after some other word foobar has been created, this behavior can then be loaded in, with:
---------------------
[`] foobar is blob ---------------------
defer'd words are useful for generating recursive routines. Here's an example:
----------------------------------
defer hold2 \ Will execute action2 : action1 ... hold2 ( really action2 ) ... ; : action2 ... action1 ... ; ` action2 is hold2 ----------------------------------
defer'd 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 is .special print-em-all [`] .h is .special print-em-all [`] .sp is .special print-em-all ; ----------------------------------------------------------------
If a defer word is executed before being loaded with some behavior, an error message will be printed.
Deletes the property named by adr len in the active package, if such a property exists.
For example:
--------------------------------------------
: unmap-me ( -- ) my-reg my-size " map-out" $call-parent " address" delete-attribute ; --------------------------------------------
A defer word, called by the terminal emulator when needed to delete n 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 may be done with is, or it may be loaded automatically with fb1-install or fb8-install (which loads fb1-delete-characters or fb8-delete-characters , respectively).
A defer word, called by the terminal emulator to delete n lines starting with the cursor line (and deletes n-1 lines below the cursor). Lines above the cursor 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.
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 may be done with is, or it may be loaded automatically with fb1-install or fb8-install (which loads fb1-delete-lines or fb8-delete-lines , respectively).
+n 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.
Creates a name attribute with the given string value, for example:
---------------------------
" SUNW,zebra" device-name ---------------------------
This is equivalent to using the name macro or
-----------------------------
xdrstring " name" attribute -----------------------------
except that device-name performs the same function with only 2 bytes of FCode, instead of 10 bytes. This could be useful for devices with extremely limited FCode space.
See "name" in Chapter 5, "Properties" for more information.
This is a shorthand word for creating a "device_type" property. This property is essential for any plug-in SBus device that will be used during booting, as it tells the boot PROM which type of boot device it is. An example usage would be:
------------------------
" display" device-type ------------------------
This is exactly equivalent to the following:
-----------------------------------------------
" display" xdrstring " device_type" attribute -----------------------------------------------
Note the spelling difference between the FCode command device-type (hyphen) and the device_type property (underscore).
The device_type property is looked at and used by the boot PROM as well.
See also: "device_type" in Chapter 5, "Properties".
Returns a true flag if the diag-switch? NVRAM parameter is set to true . This word enables an FCode program to optionally perform some extended selftests, based on the diag-switch? . 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.
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 ( adr cnt -- ) bounds ?do i c@ d# 16 digit if probe-slot else drop then loop ; ------------------------------------------------------------
Display the results of some test. The method of display is system-dependent. This FCode is obsolete and should not be used.
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. 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 -----------------------------------------
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 may be used in place of do in nearly all circumstances.
Used to allocate memory for DMA usae. The allocated memory may be returned to the system with free-virtual.
This FCode is obsolete on OpenBoot 2 PROMs. For use under OpenBoot 1, see Appendix D, "Changes in OpenBoot 1 FCode Usage".
For version 2 OpenBoot systems, use " dma-alloc" method of parent:
----------------------------
" dma-alloc" $call-parent " dma-map-in" $call-parent ----------------------------
For example:
----------------------------------------------------
: my-dma-alloc ( -- ) my-size " dma-alloc" $call-parent ( vaddr ) is my-reg ; ----------------------------------------------------
A defer word, called by the boot PROM's 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 may be done with is, or it may be loaded automatically with fb1-install or fb8-install (which loads fb1-draw-character or fb8-draw-character , respectively).
A defer word, called by the system to display the power-on logo (the graphic displayed on the left side during power-up, or by the banner Toolkit command).
This word is initially empty, but must be loaded with an appropriate routine in order for the terminal emulator to function correctly. This may be done with is, or it may 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 reinitialize 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. See Appendix D, "Changes in OpenBoot 1 FCode Usage". For general use, also see Appendix C, "FCode Memory Allocation".
laddr - 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 a built-in Sun logo. In either case, the logo is a bit array of 64x64 (decimal) pixels (512 bytes). The most significant bit (msb) of the first byte represents the upper-left pixel; msb-1 represents the next pixel to the right, and so on. A bit value of 1 means that pixel will be painted.
lwidth - The width of the passed-in logo (in pixels).
lheight- The height of the passed-in logo (in pixels).
This is an obsolete word for creating a name property.
driver is no longer supported and should not be used in FCode programs.
Removes one item from the stack.
Removes two items from the stack.
Removes three items from the stack.
Duplicates the top stack item.
Duplicate the top stack item unless it is zero.
Duplicates the top two stack items.
Duplicates the top three stack items.
Begin the else clause of an if ... else ... then statement. See if for more details.
A defer word that outputs the indicated ASCII character. For example, (hex) 41 emit outputs an "A", 62 emit outputs a "b", 34 emit outputs a "4".
A tokenizer 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.
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 version h# 20000 < if ['] end0 execute then ; ---------------------------------------------------------------------
An alternate word for end0 , to mark the end of an FCode program. end0 is recommended.
Marks the end of a case statement. See case for more details.
Marks the end of an of clause within a case statement. See case for more details.
Sets len bytes of memory beginning at adr to zero. No action is taken if len is zero.
A defer word, 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 framebuffer 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 may be done with is, or it may be loaded automatically with fb1-install or fb8-install (which loads fb1-erase-screen or fb8-erase-screen , respectively).
Executes Forth commands within a string. The overall stack effect depends on the commands being executed. For example:
----------------------
" 4000 20 dump" eval ----------------------
You can use eval like $find, to find and execute Forth commands that are not FCodes.
The same cautions apply to eval as for $find, in that programs executing Forth commands are likely to encounter portability problems when moved to other systems.
Executes the word definition whose compilation address is acf . An error condition exists if acf is not a compilation address.
For example:
-----------------------------------
: my-word ( adr len -- ) ." Given string is: " type cr ; " great" ['] my-word execute -----------------------------------
Compiled within a colon definition. When encountered, execution leaves the current word and returns control to the calling word. May not be used within a do loop.
For example:
----------------------------------------------------------
: probe-loop ( adr -- ) \ generate a tight probe loop until any key is pressed. begin dup l@ drop key? if drop exit then again ; ----------------------------------------------------------
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 adr proceeding towards higher addresses one byte per character until either a return is received or until len characters have been transferred. No more than len characters will be stored. The 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 ; ----------------------------------------------------------------
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
external stays in effect until headers or headerless is encountered.
For example:
-------------------------
external : open ( -- ok? ) ... ; -------------------------
A token-type, 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.
Leave the value for the false flag (which is zero) on the stack.
The built-in default routine to blink or flash the screen momentarily on a generic 1-bit-per-pixel framebuffer. 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 framebuffer FCode program to replace fb1-blink-screen with a custom routine that simply disables the video for 20 milliseconds or so, i.e.
------------------------------------------------------------
: my-blink-screen ( -- ) video-off 20 ms video-on ;
... fb1-install ... ['] my-blink-screen is blink-screen ------------------------------------------------------------
The built-in default routine to delete n characters at and to the right of the cursor, on a generic 1-bit-per-pixel framebuffer. 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.
The built-in default routine to delete n lines, starting with the cursor line, on a generic 1-bit-per-pixel framebuffer. 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 cursor line and n-1 lines below it 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.
The built-in default routine for drawing a character on a generic 1-bit-per-pixel framebuffer, 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.
The built-in default routine to draw the logo on a generic 1-bit-per-pixel framebuffer. 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.
The built-in default routine to clear (erase) every pixel in a generic 1-bit-per- pixel framebuffer. 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.
The built-in default routine to insert n blank characters to the right of the cursor, on a generic 1-bit-per-pixel framebuffer. 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 ).
The built-in default routine to insert n blank lines below the cursor on a generic 1-bit-per-pixel framebuffer. 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.
This built-in routine installs all of the built-in default routines for driving a generic 1-bit-per-pixel framebuffer. 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 also initialized:
screen-width - set to the value of the passed-in parameter screen- width (screen width in pixels)
screen-height - set to the value of the passed-in parameter screen- height (screen height in pixels)
#columns - set to the smaller of the following two: the passed-in parameter #cols , 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.
The built-in default routine to invert every visible pixel on a generic 1-bit-per- pixel framebuffer. 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).
The built-in default routine to enable a generic 1-bit-per-pixel framebuffer 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 is reset-screen ---------------------------------------
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 framebuffers 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.
The built-in default routine to toggle the cursor location in a generic 1-bit-per- pixel framebuffer. 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.
The built-in default routine to blink or flash the screen momentarily on a generic 8-bit-per-pixel framebuffer. 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 framebuffer FCode program to replace fb8-blink-screen with a custom routine that simply disables the video for 20 milliseconds or so, i.e.
------------------------------------------------------------
: my-blink-screen ( -- ) video-off 20 ms video-on ; ... fb8-install ... ['] my-blink-screen is blink-screen ------------------------------------------------------------
---------------------------------------
: my-video-enable ( -- ) ... : fb8-install ... ['] my-video-enable is reset-screen ... ---------------------------------------
This FCode is obsolete, use version instead.
This word, or fcode-version2, must be the first command in your FCode program (except for tokenizer directives such as hex or \ that do not generate any FCode bytes). The command fcode-version1 creates an 8-byte header, as:
----------------------------------
(fd) version1 ( 1 byte ) (00) null byte ( 1 byte ) (xxyy) reserved ( 2 bytes ) (aabbccdd) length ( 4 bytes ) ----------------------------------
The length field specifies the total usable length of FCode data, from version1 to end0 inclusive. Additional end0 bytes are appended to the end of the data, if needed, to leave a total length which is evenly divisible by 4. The "null byte" position may be used in the future to carry a version number or other information, but it is currently not used.
See Appendix D, "Changes in OpenBoot 1 FCode Usage".
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.
Caution - In most cases, use fcode-version1, along with an escape routine to prevent any version 1.0 systems from trying to execute, as shown in the following example:
----------------------------------------------------------------
: ?quit ( -- ) version h# 2.0000 < if ['] end0 execute then ; ?quit ----------------------------------------------------------------
See Appendix D, "Changes in OpenBoot 1 FCode Usage".
Displays an "Unimplemented FCode" error message and stops FCode interpretation. All unimplemented FCode numbers resolve to ferror in all existing OpenBoot implementations.
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? ( acf -- flag) [`] ferror < ; : my-peer ( prev -- next ) [`] peer implemented? if peer else ." peer is not implemented" cr then : ----------------------------------------------
struct and field are used to create named offset pointers into some array structure. For each field in the array structure, a name is assigned to the location of that field (as an offset from the beginning of the array). Here's a code example. (The numbers in parentheses show the stack after each word is created.) The structure being described is:
---------------------------------------------------------------------
byte# 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 size flags.. bits key fullname.................... age initials lastname........... 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 merely a cross-compiler equivalent that puts the number 0 on the stack.
Set u bytes of memory beginning at adr to byte . No action taken if u = 0.
Takes a string from the stack, and tries to find that word in the OpenBoot PROM. This is an escape hatch, allowing an FCode program to perform any function that is available in the OpenBoot Forth Monitor but that is not defined as part of the standard FCode interface.
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 code field address of that word is left on the stack, and either a +1 or -1 is left on top. +1 is left if the found word is an immediate word, -1 is left otherwise.
Use $find with caution! Different CPUs or even different versions of the boot PROM may change or delete certain words in the Toolkit. If your FCode program depends on one of these words, you may suddenly find that your SBus card doesn't work properly with future releases.
Caution - If you find yourself tempted to use $find , please contact the Sun SBus Support Group and tell them what function you need to use this way. This will help Sun to plan for future FCode features, and will let you know the likelihood of the needed Toolkit word being changed in the future.
Example of use:
--------------------------------------------------------------
" root-info" $find ( adr len false | acf +/-1 ) if execute \ if found, then do the function \ in this example, we don't care about \ immediate vs. non-immediate else ( adr len ) type ." was not found!" cr then --------------------------------------------------------------
Locates the method named by adr len within the package phandle. Returns
false
For example:
----------------------------------------------
: tftp-load-avail? ( -- exist? ) " obp-tftp" find-package if ( phandle ) " load" rot find-method if ( acf ) drop true exit then then false ; ----------------------------------------------
Locates a package whose name is given by the string adr len. If the package
can be located, returns its phandle and
For example:
----------------------------------------------
: tftp-load-avail? ( -- exist? ) " obp-tftp" find-package if ( phandle ) " load" rot find-method if ( acf ) drop true exit then then false ; ----------------------------------------------
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 SunOS device drivers. Typical usage:
---------------------------------------------------
fcode-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 fcode-version1 or fcode-version2), 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.
Returns a 32-bit number identifying the version of the CPU firmware. The high 16 bits is the major version number and the low 16 bits is the minor version number.
This is the major/minor release number that is accessed by the ROMvec
entry op_mon_id
For example:
--------------------------------------------------------------------
: show-version ( -- ) ." CPU bootprom version is " base @ d# 16 base ! ( old-base ) firmware-version ( old-base version ) lwsplit (.) type ascii . emit .h cr base ! ( ) ; --------------------------------------------------------------------
n2 is the result of exchanging the two low-order bytes of the number n1 . The two upper bytes of n1 must be zero, or erroneous results will occur.
Tokenizer command that begins tokenizing text in the named file. When the named file is done, tokenizing continues on the file that called filename with fload.
For example:
----------------------------
fload my-disk-package.fth ----------------------------
fload commands may be nested; an floaded file may include fload commands.
fload is useful for creating large FCode programs, making it easier to break them up into function blocks for better clarity and portability.
Note - fload commands won't work when downloading text in source-code form. You can either manually merge your text into one big file, download and execute the various file separately, or tokenize it first and then download and execute the FCode in binary form.
------------------------------------------------------------------
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-sbus is frame-buffer-adr ; : video-unmap ( -- ) frame-buffer-adr /frame free-virtual -1 is 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 ------------------------------------------------------------------
Frees up memory allocated by alloc-mem .
For example:
-------------------------------------------------------------------
0 value my-string \ Holds address of temporary : .upc-string ( adr len -- ) \ convert to uppercase and print. dup alloc-mem is my-string ( adr len ) tuck my-string swap cmove ( len ) my-string over bounds ?do i c@ upc i c! loop ( len ) my-string over type ( len ) my-string swap free-mem ; -------------------------------------------------------------------
Undoes the MMU page map entries generated by obsolete FCodes memmap , dma-alloc , or map-sbus .
This FCode is obsolete for OpenBoot 2. (For use under OpenBoot 1, see Appendix D, "Changes in OpenBoot 1 FCode Usage".) To undo maps created with " map-in" $call-parent use:
-------------------------
" map-out" $call-parent -------------------------
and to undo maps created with " dma-map-in" $call-parent use :
-----------------------------
" dma-map-out" $call-parent -----------------------------
to undo maps created with " dma-alloc" $call-parent" use::
--------------------------
" dma-free" $call-parent --------------------------
Locates, within the package associated with the current instance or any of its
parents, the property whose name is name-adr name-len. If the property
exists, returns the property value array xdr-adr xdr-len and
The order in which packages is 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.adr len false | true ) " clock-frequency" get-inherited-attribute ; ----------------------------------------------------------
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 many systems (including the SPARCstation 1), the value is derived from the system clock, which typically ticks once per second. Thus, the value returned by get-msecs on the SPARCstation 1 and 1+ will be seen to increase in jumps of 1000 (decimal), once per second. For a delay timer of millisecond accuracy, see ms .
Locates, within the package associated with the current instance, the property
named by name-adr name-len. If the property exists, returns the property
value array val-adr val-len and false
For example:
-------------------------------------------------------
: show-model-name ( -- ) " model" get-my-attribute 0= if ( val.adr len ) ." model name is " type cr else ( ) ." model attribute is missing " cr then ( ) ; -------------------------------------------------------
Locates, within the package phandle, the property named by name-adr name-len. If the property exists, returns the property value array xdr-adr xdr-len and false. Otherwise returns true.
For example:
----------------------------------------------------------------
: show-model-name ( -- ) my-self ihandlephandle ( phandle ) " model" rot get-package-attribute 0= if ( val.adr len ) ." model name is " type cr else ( ) ." model attribute is missing " cr then ( ) ; ----------------------------------------------------------------
This FCode is obsolete and should not be used.
Displays n in hex (using . ) The value of base is not permanently affected.
Interpret the next number in hex (base 16), regardless of any previous settings of hex, decimal, binary, or octal. Only the immediately following number is affected, the default numeric base setting is unchanged. For example:
---------------------------------
decimal h# 100 ( equals decimal 256 ) 100 ( equals decimal 100 ) ---------------------------------
See also b#, d#, and o#.
Causes all subsequent definitions to be created in FCode 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 may be used normally within the FCode program, but cannot be called interactively from the Toolkit for testing and development purposes.
Unless PROM space and/or dictionary space is a major consideration, Sun recommends 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 --------------------------
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 Toolkit 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 ; --------------------------
adr is the address of the next available dictionary location.
If outside of a definition, commands the tokenizer program to interpret subsequent numbers in hex (base 16). If within a definition, change the value in base affecting later numeric output when the FCode program is executed. See base .
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 ; --------------------------------------------
n 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 ; ----------------------------------
Execute the following code if flag is true. Used in the form:
---------------------------
flag if ... else ... then ---------------------------
or
------------------
flag if ... then ------------------
If flag is true, the words following if are executed and the words following else are skipped. The else part is optional. If flag is false, words from if through else , or from if through then (when no else is used), are skipped.
Returns the phandle of the package from which the instance ihandle was created. This is often used with get-package-attribute to read the properties of the package corresponding to a given ihandle.
For example:
------------------------------------------
: show-parent ( -- ) my-parent ihandlephandle " name" rot get-package-attribute 0= if ." my-parent is " type cr then ; ------------------------------------------
Used to declare that new versions of data should be created for each new instance of a package (as opposed to global data). Valid for FCode version 2.1 or later.
instance should be called just before the data-creation defining word. Valid uses are with value, variable, defer and buffer:. For example:
---------------------------------------------------------
: instance ( -- ) \ verify if "instance" is implemented. ['] instance ['] ferror < if instance then ; -1 instance value my-chip-reg ---------------------------------------------------------
This is a shorthand word for declaring the "intr" and "interrupts" properties.
See "intr" and "interrupts" in Chapter 5, "Properties".
See also attribute .
Changes the contents of a value or a defer word:
------------------------------------------
number is name ( for a value ) acf is name ( for a defer word ) ------------------------------------------
Creates open, write, and draw-logo methods for display devices.
For any SBus framebuffer 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 framebuffer. 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:
-----------------------------------------------------------------
fcode-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 -----------------------------------------------------------------
Creates a close method for display devices.
Declares the routine that will deallocate a framebuffer that is no longer going to be used. Typical deallocation would include unmapping memory and clearing buffers. For example:
------------------------------------------------------------
fcode-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" routine ['] 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.
Creates a selftest method for display devices.
Declares the routine that will perform a self test of the framebuffer. For example:
------------------------------------------------------------
FCode-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 40.
Creates a Forth word (not a package method) whose name is given by adr
len, and whose behavior is given by the compilation address acf (as returned
by [']
For example:
-------------------------------------
" xyz-abort" ' my-abort (is-user-word) -------------------------------------
n is a copy of the index of the next outer loop. May only be used within 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.
A defer word that reads the next ASCII character from the keyboard. If no character has been typed since key 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 ; --------------------------------------------------
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, interruptable infinite loops:
------------------------
begin ... key? until ------------------------
The contents of the loop will repeat indefinitely until any key is pressed.
The 32-bit value n is stored at location adr (through adr+3 ). The highest byte is stored at adr ; the lowest byte is stored at adr+3 . adr must be on a 32-bit boundary; it must be evenly divisible by 4.
Compile 4-bytes into the dictionary, starting with the highest byte. See c, for limitations. 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, -----------------------------------------------------------
Fetch the 32-bit number stored at adr (through adr+3 ). The highest byte is stored at adr ; the lowest byte is stored at adr+3 . adr must be on a 32-bit boundary; it must be evenly divisible by 4.
n is the size in bytes of a 32-bit word: 4.
n2 is the result of multiplying n1 by the length in bytes of a (32-bit) long word. This is useful for converting an index into a byte offset. /l* is equivalent to 4 * , but should be used in preference to the less portable 4 * .
adr2 is the address of the index'th 32-bit longword after adr1 . For byte- addressed machines (such as this one), this is equivalent to 4 * + .
Use la+ in preference to the less portable and less clear 4 * + .
adr2 is the address of the next 32-bit word after adr1 . For byte-addressed machines (such as this one), this is equivalent to 4 + . la1+ should be used in preference to the less portable and clear 4 + .
Splits a 32-bit value into four bytes. The upper bits of each byte are all zeroes.
char2 is the lower case version of char1 . If char1 is not an upper case letter, it is unchanged. See upc .
For example:
---------------------
ascii M lcc emit ---------------------
shows m .
Transfers execution to just past the next loop or +loop . The loop is terminated and loop control parameters are discarded. May only be used within a do or ?do loop.
leave may appear within other control structures that are nested within the do loop structure. More than one leave may appear within a do loop.
For example:
----------------------------------------------------
: search-pat ( pat adr len -- found? ) rot false swap 2swap ( false pat adr len ) bounds ?do ( flag pat ) i @ over = if drop true swap leave then loop drop ; ----------------------------------------------------
If flag 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 flag is zero, no action is taken. May only be used within a do or ?do loop.
?leave may appear within other control structures that are nested within the do loop structure. More than one ?leave may appear within a do loop.
For example:
--------------------------------------------------------------
: show-mem ( vadr -- ) \ 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 ; --------------------------------------------------------------
A tool for separating fields within a string. 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 within 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".
Swaps the order of the 16-bit words within each 32-bit longword in the memory buffer adr len. adr must be four-byte-aligned. len must be a multiple of four.
For example:
---------------------
h# 12345678 8000 l! 8000 4 lflips 8000 l@ .h ---------------------
shows 56781234 .
A variable that increments whenever cr executes. #line @ returns the current value of this variable . 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.
----------------------------------------------------------------
: set-line ( line -- ) 0 max #lines 1- min is line# ; ----------------------------------------------------------------
n is the ASCII code for the linefeed character; decimal 10, hex 0a .
----------------------------------------------------------------
: set-line ( line -- ) 0 max #lines 1- min is line# ; ----------------------------------------------------------------
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 to 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.
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 to 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.
Tries to read the 32-bit longword at address adr. Returns the data and true if the access was successful. A false return indicates that a read access error occurred. adr must be 32-bit aligned.
Tries to write the 32-bit longword at address adr. Returns the data and true if the access was successful. A false return indicates a read access error. adr must be 32-bit aligned.
Note - lpoke may be unreliable on bus adapters that "buffer" write accesses.
Tokenizer instruction that zero-extends a 32-bit number to 64-bit.
Splits the 32-bit value n into two 16-bit words. The upper bits of the two generated words are zeroes.
Usually used only by the network device-type, this FCode returns the value for the Media Access Control, or MAC address, that this SBus card should use for its own address. The data is encoded as a byte array, generally 6 bytes long.
The value returned by mac-address can either be supplied by the system, or by the card itself. If the card's FCode creates a property named local-mac- address, and the NVRAM parameter local-mac-address? (for typical systems) is set to true, then the value contained in the property local-mac- address will be returned by mac-address. Otherwise, the system will assign a value.
See also "mac-address", "local-mac-address", and "network" in Chapter 5, "Properties" and Chapter 9, "Network Devices".
This FCode is obsolete in version 2. For version 1 usage, see Appendix D, "Changes in OpenBoot 1 FCode Usage".
For version 2, use:
------------------------
" map-in" $call-parent ------------------------
Creates a memory mapping for some SBus locations, usually within the address space of this SBus card. The MMU page maps are updated, and the generated virtual address is returned.
The memory mapping can (and should) be later undone with free-virtual. Used as:
--------------------------
( -1 value vregs ) ... my-address 10.0000 + 100 map-sbus ( virt ) is vregs --------------------------
This variable controls which bits out of every 32-bit longword which will be tested with 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 longword, set just the lower bits of mask with:
---------------------
0000.00ff mask ! ---------------------
Any arbitrary combination of bits may be tested or masked.
n3 is the greater of n1 and n2.
Creates a memory mapping for some locations. It updates MMU page maps and returns the generated virtual address. The actual physical address is specified by ( physoffset space ), that indicates the device space and the physical offset within that space.
This fcode is obsolete in OpenBoot 2. For OpenBoot 1 usage, refer to Appendix D, "Changes in OpenBoot 1 FCode Usage". For version 2, use:
------------------------
" map-in" $call-parent ------------------------
The memory mapping can (and should) be later undone with free-virtual.
Performs a series of tests on some memory, to verify its proper functioning. A true flag is returned if any of the tests failed.
If diagnostic-mode? is true ( diag-switch? NVRAM parameter is true), then a message is sent out to the current output device (to ttya if during probe time) giving the name of each test. If any test fails, a "Failed" message will also then be displayed.
For every one of the following tests, the value stored in the variable mask controls whether only some or all data lines are tested.
For example, to only test data bits 0-23 (skipping bits 24-31), mask would be set with: 00ffffff mask !
The actual tests performed may vary from system to system. On current systems, the tests performed are:
The above tests are very fast. If the diag-switch? NVRAM parameter is set to true , then the following (slower) additional tests are also performed:
For example:
-------------------------------------------------------------------
: test-result ( -- ) frame-buffer-adr my-frame-size memory-test-suite ( failed? ) xdrint " test-result" attribute ; -------------------------------------------------------------------
n3 is the lesser of n1 and n2 .
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.
Calculates n1 * n2 / n3 , 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.
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.
This is a shorthand word for creating a model property. By convention, model identifies the model name/number for an SBus card, for manufacturing and field-service purposes. A sample usage would be:
-------------------------
" SUNW,501-1415" model -------------------------
This is equivalent to:
-------------------------------------------------
" SUNW,501-1415" xdrstring " model" attribute -------------------------------------------------
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 SunOS device driver).
See also attribute , "model" in Chapter 5, "Properties".
len bytes starting at adr1 (through adr1+len-1 inclusive) are moved to address adr2 (through adr2+len-1 inclusive). If len is zero then nothing is moved.
The data are moved such that the len bytes left starting at address adr2 are the same data as was originally starting at address adr1 . If adr1 adr2 then the first byte of adr1 is moved first, otherwise the last byte (len'th) of adr1 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.
Delays all execution for the specified number of 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 ( adr -- ) \ wait h# 10 ms before doing another probe at the location begin dup l@ drop h# 10 ms key? until drop ; ------------------------------------------------------------
Returns a magic number, suitable for use with the map-in method, and with reg, xdrphys, map-sbus and memmap. The returned number, along with my- space, encodes the address of location 0 of this SBus device. The OpenBoot PROM automatically sets my-address to the correct value before each SBus slot is probed.
For example:
-----------------------------------------------
fcode-version1 " audio" xdrstring " name" attribute my-address h# 130.0000 + my-space h# 8 reg ... end0 -----------------------------------------------
Returns the argument string adr 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:
---------------------------------
" /obio:TEST-ARGS" select-dev my-args type ---------------------------------
The above will display arguments passed to /obio at open time as TEST- ARGS
This fcode is obsolescent and should not be used.
my-params returns a string that contains arbitrary customization information for this device. The string comments are the contents of the params property if present, otherwise returns a null string (adr,len equals 0,0).
my-args may be used in some situations to perform the same function.
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:
------------------------------------------
: show-parent ( -- ) my-parent ihandlephandle " name" rot get-package-attribute 0= if ." my-parent is " type cr then ; ------------------------------------------
Returns the current instance ihandle.
For example:
--------------------------------------------------------------
: show-model-name ( -- ) my-self ihandlephandle ( phandle ) " model" rot get-package-attribute 0= if ( val.adr,len ) ." model name is " type cr else ( ) ." model attribute is missing " cr then ( ) ; --------------------------------------------------------------
Returns a "magic" number, representing the device space that this SBus card is plugged into.
For example:
-----------------------------------------------
fcode-version1 " audio" xdrstring " name" attribute my-address h# 130.0000 + my-space h# 8 reg ... end0 -----------------------------------------------
See my-address for more details.
Returns the unit address low high of the current instance. The unit address is set when the instance is created, as follows:
For example. on SPARCclassic systems:
------------------------------------------------------
" /iommu/sbus/ledma@4,840010" select-dev my-unit .s ------------------------------------------------------
displays
-------------
840010 4 -------------
The number of bytes in a normal stack item; 4 in this implementation.
n2 is the result of multiplying n1 by the length in bytes of a normal stack item. This is useful for converting an index into a byte offset. This word is equivalent to 4 * .
adr2 is the address of the index'th "normal" sized word after adr1 . For this implementation, this is equivalent to 4 * + .
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.
adr2 is the address of the next "normal" sized word after adr1 . For this implementation, this is equivalent to 4 + or la1+ .
na1+ 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.
A shorthand word for creating a "name" property, used to match a device node with the appropriate SunOS driver. The "name" declaration is required for booting with SunOS, and should be present in every FCode program. For example:
--------------------
" SUNW,bison" name --------------------
is equivalent to:
-------------------------------------------
" SUNW,bison" xdrstring " name" attribute -------------------------------------------
See also attribute , device-name.
See "name" in Chapter 5, "Properties".
named-token, external-token or new-token are called to create a new dictionary entry. If headers are active, use named-token.
The new header for a word created with named-token has the following format:
---------------------------------------
named-token, string, new FCode#, type ---------------------------------------
The first byte is b6, indicating a named-token format.
named-token should never be used directly in source code.
n2 is the opposite sign of n1 . This is equivalent to -1 * .
Start a new entry in the device tree. This word is used for creating multiple devices in a single FCode program. See finish-device.
named-token, external-token or new-token are called whenever a new dictionary entry is to be created. If headerless is active, then use new- token.
The format for new-token is identical to that for named-token , except that the string field is missing (and the first byte is b5 instead of b6 ). See named-token for more details.
new-token should never be used directly in source code.
n is the ASCII code for the character that terminates a line; decimal 10, hex 0a. In this system this is the linefeed character.
newline is system-dependent, so its use is discouraged. Usually, it doesn't increment the line count, that results in problems with correct screen scrolling. Use of cr instead of newline is usually appropriate.
Remove the second item on the stack.
Do nothing. This can be used to waste time or as a placeholder for something that will be patched in later.
n2 is the one's complement of n1 , i.e. all the one bits in n1 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=.
A numeric conversion primitive that converts a string to a number, according to the current base value (usually hexadecimal). An error flag is returned if an inconvertible character is encountered. For example, " 123f" $number returns 123f 0 on the stack, while "123x" returns -1, indicating that the conversion failed.
For example:
---------------------------------------------------
: number-or-0 ( adr len -- true | number false ) dup if $number else 2drop 0 false then ; ---------------------------------------------------
Interpret the next number in octal (base 8), regardless of any previous settings of hex, decimal, binary, or octal. Only the immediately following number is affected, the default numeric base setting is unchanged. For example:
------------------------------
hex o# 100 ( equals decimal 64 ) 100 ( equals decimal 256 ) ------------------------------
See also b#, d#, and h# .
If outside a definition, commands the tokenizer program to interpret subsequent numbers in octal (base 8). If within a definition, changes the value in base , affecting later numeric output when the FCode program is executed. See base.
Begin the next test clause in a case statement. See case for more details.
Set the 32-bit contents at adr to zero ( false ).
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.
Set the 32-bit contents at adr to -1 or ffff.ffff ( true ).
Creates an instance of the package identified by phandle, saves in that instance an argument string specified by arg-adr 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 ; ----------------------------------------------------------
Similar to using find-package open-package, except that if find- package fails, 0 is returned immediately, without calling open-package .
For example:
----------------------------------------------
0 0 " obp-tftp" $open-package ( ihandle ) ----------------------------------------------
n3 is the bit-by-bit inclusive-or of n1 with n2 .
A variable containing the current column number on the output device. This is updated by emit and some other words that modify the cursor position. It is used for display formatting.
For example:
--------------------------------------------------------
: to-column ( column -- ) #out @ - 1 max spaces ; --------------------------------------------------------
The second stack item is copied to the top of the stack.
Copies the third and fourth stack items to the stack top.
Convert a byte array (indicated by " adr len ") into a packed string, and store it at the location pstr . 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 " adr len " format.
For example:
------------------------------------------------
h# 20 buffer: my-packed-string " This is test string " my-packed-string pack ------------------------------------------------
peer returns the phandle next-phandle of the package that is the next child of the parent of the package phandle.
If phandle is the last child of its parent, peer returns zero.
If phandle is zero, 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 ; -------------------------------------------------
Given a virtual address, return the mapped physical address as a ( physoffset space ) pair, specifying the device space (as a "magic number") and the physical offset within that space.
This word has inconsistent behavior in current boot PROMs, and you should avoid using it in FCode programs.
For example:
-----------------------------------------------------------------
: in-ram? ( vadr -- phys flag ) physical ( padr space ) \ code-to-verify if space and address refer to on-board memory ; -----------------------------------------------------------------
n2 is a copy of the +n'th stack value, not counting +n itself. +n must be between 0 and the number of elements on the stack-1 inclusive.
------------------------------------------------------
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 readability's sake, the use of pick should be minimized.
This FCode is obsolete, and should not be used. Use probe-self method of a hierarchical device node.
This FCode is obsolete, and should not be used. Use " set-args" and "byte-load" as shown below. In case you have downloaded the FCode PROM image of a SBus device at virtual address 4000, and the device is in SBus slot #1 use:
----------------------------------------------------------------------
" /sbus" select-dev new-device 0 0 " 1,0" " set-args" $find if ( arg-str reg-str acf ) execute 4000 1 " byte-load" $find if ( adr offset acf ) execute else ." byte-load missing " cr 2drop 2drop then else ." set-args missing " cr 2drop 2drop 2drop then finish-device unselect-dev ----------------------------------------------------------------------
Returns the type of processor (instruction set architecture). Obsolete.
n1 is converted using the value of base and then displayed right aligned in a field +n characters wide. A leading minus sign is displayed if n is negative. A trailing space is not displayed.
If the number of characters required to display n1 is greater than +n, an error condition exists. In this implementation, all the characters required will be displayed, making the resulting field larger than +n.
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 ; ---------------------------------------
Removes n from the return stack and places it on the (regular) stack. See >r for restrictions on the use of this word.
For example:
--------------------------------------------------------
: copyout ( buf adr len -- len ) r swap r@ move r ; --------------------------------------------------------
n is a copy of the top of the return stack.
For example:
--------------------------------------------------------
: copyout ( buf adr len -- len ) r swap r@ move r ; --------------------------------------------------------
See >r for more details.
Removes n 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. 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.
For example:
--------------------------------------------
: xdrintr ( int-level vector -- ) r sbus-intrcpu xdrint r xdrint xdr+ ; --------------------------------------------
Some restrictions that must be observed are:
Stores an 8-bit byte, preserving bit order.
For example:
----------------------------------------
: my-stat! ( byte -- ) my-stat rb! ; ----------------------------------------
Fetches an 8-bit byte, preserving the bit order.
For example:
---------------------------------------
: my-stat@ ( -- byte ) my-stat rb@ ; ---------------------------------------
This is a shorthand word for declaring a property named "reg" (by convention, reg is used for declaring the location and size of device registers). Typical usage:
--------------------------------------------
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 xdrphys 20 xdrint xdr+ " reg" attribute --------------------------------------------
Note that if you need to declare more than one block of register addresses, you must use the longer, more explicit method in order 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, use the following:
----------------------------------------------------------------
my-address 10.0000 + my-space xdrphys \ Offset#1 100 xdrint xdr+ \ Merge size#1 my-address 20.0000 + my-space xdrphys xdr+ \ Merge offset#2 380 xdrint xdr+ \ Merge size#2 " reg" attribute ----------------------------------------------------------------
See also attribute. See also "reg" in Chapter 5, "Properties".
Terminates a begin ... while ... repeat conditional loop.
See while for more details.
---------------------------------------
['] my-video-on is reset-screen ---------------------------------------
Stores a 32-bit longword, preserving bit order. adr must be 32-bit aligned.
For example:
----------------------------------
: my-reg! ( n -- ) my-reg rl! ; ----------------------------------
Fetches a 32-bit longword, preserving bit order. adr must be 32-bit aligned.
For example:
----------------------------------
: my-reg@ ( -- n ) my-reg rl@ ; ----------------------------------
The +n'th stack value, not counting +n itself, is first removed and then transferred to the top of the stack, moving the remaining values into the vacated position. +n must be between 0 and the number of elements on the stack-1, inclusive.
----------------------------------------------------------------
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 readability's sake, minimize your use of roll. It is also relatively slow.
Rotates the top three stack entries, bringing the deepest to the top.
Rotates the top three stack entries in the direction opposite from rot , putting the top number underneath the other two.
Rotates the top three pairs of numbers, bringing the third pair to the top of the stack.
Stores a 16-bit word, preserving bit order. adr must be 16-bit aligned.
For example:
--------------------------------------
: my-count! ( w -- ) my-count rw! ; --------------------------------------
Fetches a 16-bit word, preserving bit order. adr must be 16-bit aligned.
For example:
--------------------------------------
: my-count@ ( -- w ) my-count rw@ ; --------------------------------------
Displays the absolute value of n in a free-field format with a leading minus sign if n is negative. A trailing space is also displayed. Even if the base is hexadecimal, the number will be printed in signed format (see . ).
+l 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 the number 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.
Ignore subsequent text after the (s up to a delimiting ) . The same behavior occurs for ( .
Although either ( or \ works equally well for documentation, by common convention we use ( ... ) or (s ... ) for stack comments and \ ... for all other text comments and documentation.
Use (s to distinguish a definition's "interface" stack comment from stack comments within a definition (which clarify the current stack state). (This distinction could be of use for implementing automatic stack-checkers.) For example:
---------------------------------------
\ map in registers : map-regs (s size -- virt ) reg-addr swap ( addr size ) map-sbus ( virt ) ; ---------------------------------------
Displays the contents of the data stack (using . ) in the current base. The top of the stack appears on the right. The contents of the stack are unchanged.
For example:
-------------------------------------------------
: debug-abtest ( ??? -- ??? ) debug-on? if ." input params: " .s cr then abtest debug-on? if ." output params: " .s cr then ; -------------------------------------------------
Convert the SBus interrupt level (1-7) to the CPU interrupt level. The mapping performed will be system-dependent.
This word is called by the intr command.
For example:
-----------------------------------------------------------
3 sbus-intrcpu xdrint 0 xdrint xdr+ " intr" attribute -----------------------------------------------------------
See "intr" in Chapter 5, "Properties".
If n is negative, appends an ASCII "-" (minus sign) to the pictured numeric output string. Typically used between <# and #'> . See (.) for a typical usage.
Display a single space character.
Display +n space characters. Nothing is displayed if +n is zero.
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 ; ----------------------------------------------------------------
Four version 2.0 FCodes whose function is similar to version1, but for use with version 2.0 FCode programs. Their use is as follows:
Initializes a struct ... field structure. See field for details.
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 may 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:
--------------------------------------------------
fcode-version1 " SUNW,my-name" name " SUNW,my-model" xdrstring " model" attribute suspend-fcode ... end0 --------------------------------------------------
This feature is intended to save memory space and reduce the system startup time by preventing the compilation of FCode drivers that are not actually used.
Exchanges the top two stack items.
Exchanges the top two pairs of stack items.
Terminate an if ... then or an if ... else ... then conditional structure. See if for more details.
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.
This is a tokenizer command, used to end FCode byte generation and interpret following text as tokenizer commands (up to the closing ]tokenizer ). A tokenizer[ ... ]tokenizer sequence may be used anywhere in an FCode program, either within 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 ... -----------------------------------------
Another use for tokenizer[ is together with emit-byte , to manually 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 ... ----------------------------------------------------------
Ends a tokenizer-only command sequence. See tokenizer[ .
Leave the value for the true flag (which is -1) on the stack.
Copy the top stack item underneath the second item.
A defer word that transfers len characters to the output, beginning with the character at address adr , continuing through len consecutive addresses. No action is taken 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 ; ----------------------------------------------------------------
The output may go either to a framebuffer or to a serial port, depending on which is enabled.
Display n as an unsigned number in a free-field format, using the current value for base . A trailing space is also displayed.
For example:
------------
hex -1 u. ------------
shows
-----------
ffff.ffff -----------
This is a numeric conversion primitive, used to implement display words such as u. . It converts an unsigned number into a string.
For example:
--------------------
hex d# -12 (u.) type --------------------
shows:
-----------
fffffff4 -----------
n1 is converted using the value of base and then displayed as an unsigned number right-aligned in a field +n characters wide. A trailing space is not displayed.
If the number of characters required to display n1 is greater than +n, an error condition exists. In this implementation, all the characters required will be displayed, making the resulting field larger than +n.
For example:
-----------------------------------------
: formatted-output ( -- ) my-base h# 8 u.r ." base" cr my-offset h# 8 u.r ." offset" cr ; -----------------------------------------
rem is the remainder and quot is the quotient after dividing n1 by n2 . All values and arithmetic are unsigned. All values are 32-bit.
For example:
---------------
-1 5 u/mod .s ---------------
shows
--------------
0 3333.3333 --------------
n2 is the result of n1 logically shifted right one bit. A zero is shifted into the vacated sign bit.
For example:
------------
-2 u2/ .s ------------
shows
------------
7fff.ffff ------------
flag is true if n1 is less than n2 where n1 and n2 are treated as unsigned integers.
flag is true if n1 is less than or equal to n2 where n1 and n2 are treated as unsigned integers.
flag is true if n1 is greater than n2 where n1 and n2 are treated as unsigned integers.
flag is true if n1 is greater than or equal to n2 where n1 and n2 are treated as unsigned integers.
Marks the end of a begin ... ( flag ) until conditional loop. When until is encountered, a flag is removed and tested. If the flag is true, the loop is terminated and execution continues just after the until. If the flag is false, execution jumps back to just after the corresponding begin .
For example:
-----------------------------------------------------
: probe-loop ( adr -- ) \ generate tight probe-loop until a key is pressed. begin dup l@ drop key? until drop ; -----------------------------------------------------
char2 is the upper case version of char1 . If char1 is not a lower case letter, it is left unchanged. See lcc .
For example:
--------------------------------------------------
: continue? ( -- continue? ) ." Want to Continue? Enter Y/N" key dup emit upc ascii Y = ; --------------------------------------------------
Used within 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. Valid for FCode version 2.1 or later.
For example:
------------------------------------------------------------------
: test-dev-status ( -- error? ) ... ; : my-checker ( -- ) test-dev-status if user-abort then ; : install-abort ( -- ) ['] my-checker d# 10 alarm ; ------------------------------------------------------------------
Multiplies two unsigned 32-bit numbers, yielding an unsigned 64-bit product.
For example:
-------------
hex 3 3 u*x .s -------------
gives
---------
9 0 ---------
while
----------------------
4 ffff.ffff u*x .s ----------------------
gives
---------------
ffff.fffc 3 ---------------
Creates a named, value-type variable. The name is initially created with:
-----------------
456 value black -----------------
where the number before value is the initial value for black. Later occurrences of black will leave the correct value on the stack.
You can change the numeric contents of a value variable with is , as follows:
--------------
123 is black --------------
value-type variables are widely used in this system.We encourage the use of values instead of variables. values act similarly to constants or colon definitions, in that execution of the word leaves the desired number on the stack. (With a variable, you always have to do a @ .)
Create a named, variable-type variable. The name is initially created with:
--------------
variable red --------------
Later occurrences of red leave an address on the stack.
The alignment of the returned address is system-dependent.The address holds a 32-bit value. To retrieve the value in a variable and leave it on the stack for subsequent use, enter:
-------
red @ -------
To change the value in a variable , enter:
-----------
123 red ! -----------
Sun encourages the use of values instead of variables. values act like constants or colon definitions, in that execution of the word leaves the desired number on the stack. (With a variable , you always have to do a @ .) This similarity between values and other words makes the FCode easier to read, write and maintain.
Returns a 32-bit number identifying the version of the FCode interface supported by the CPU firmware. The high 16 bits is the major version number and the low 16 bits is the minor version number.
For example:
---------------------------------------------------
: exit-if-version1 ( -- ) version h# 20000 < if ['] end0 execute then ; ---------------------------------------------------
This is not the same as the OpenBoot PROM version (see firmware- version ). For example, the CPU PROM might be version 3.7, but the FCode version might still be 2.0 (= 0x00020000).
The value returned is less consistent on version 1 systems, but it is guaranteed to less than 0x0002.0000.
This byte is automatically generated by the fcode-version1 command.
Never use the word version1 in FCode source 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.
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.
Compile two bytes into the dictionary. The dictionary pointer must be two- byte-aligned.
See c, for limitations.
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.
n is the size in bytes of a 16-bit word: 2.
n2 is the result of multiplying n1 by the length in bytes of a (16-bit) word. This is useful for converting an index into a byte offset. /w* is equivalent to 2* , but should be used in preference to 2* as it is more portable.
Fetches the 16-bit number stored at adr (through adr+1 ). The higher byte is stored at adr; the lower byte is stored at adr+1 . The remaining high bytes of n are set by sign-extending the upper bit in the higher byte. adr must be two- byte-aligned.
For example:
---------------
9123 8000 w! 8000 <w@ .h ---------------
shows: ffff9123, while
------------
8000 w@ .h ------------
shows: 9123 .
adr2 is the address of the index'th 16-bit word after adr1. For byte- addressed machines (such as this one), this is equivalent to 2* + .
Use wa+ in preference to 2* + because it more clearly expresses the intent of the operation and is more portable.
adr2 is the address of the next 16-bit word after adr1 . For byte-addressed machines (such as this one), this is equivalent to 2+ . wa1+ should be used in preference to 2+ because it more clearly expresses the intent of the operation and is more portable.
Split 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.
Swap the two 16-bit halves of a 32-bit number.
Swaps the order of the bytes within each 16-bit word in the memory buffer adr len.
adr must be two-byte-aligned. len must be a multiple of two.
Test the exit condition for a begin ... (flag) while ... repeat conditional loop. When the while is encountered, a flag is removed from the stack and tested. If the flag is true , execution continues from just after the while through to the repeat which then jumps back to just after the begin. If the flag is false , the loop is exited by causing execution to jump ahead to just after the repeat .
For example:
-----------------------------------------------------
: probe-loop ( adr -- ) \ generate tight probe-loop until a key is pressed. begin key? 0= while dup l@ drop repeat drop ; -----------------------------------------------------
flag is true if n is between min and max , inclusive of min and exclusive of max . ( min <= n < max.) See between for another version.
Merge two 16-bit numbers into a 32-bit number. The high bits of each 16-bit number must be zero.
Tries to read the 16-bit half-word at address adr. Returns the data and true if the access was successful. A false return indicates that a read access error occurred. adr must be 16-bit aligned.
Tries to write the 16-bit half-word at address adr. Returns true if the access was successful. A false return indicates that a write access error occurred. adr must be 16-bit aligned.
Note: wpoke may be unreliable on bus adapters that buffer write accesses.
Adds two 64-bit numbers, leaving 64-bit sum.
For example:
---------------------------------------------
1234.0000 0056.7800 9abc 3400.009a x+ .s ---------------------------------------------
shows
----------------------
1234.9abc 3456.789a ----------------------
Subtracts two 64-bit numbers, leaving 64-bit result.
For example:
------------------
0 6 1 0 x- .s ------------------
shows
---------------
ffff.ffff 5 ---------------
and
-------------------------------------------------
4444.8888 aaaa.bbbb 2222.1111 5555.2222 x- .s -------------------------------------------------
shows
---------------------
2222.7777 5555.9999 ---------------------
Merge two xdr-format strings into a single xdr-format string. The two input strings must have been created sequentially with no intervening dictionary allocation or other xdr-format strings having been created. This can be called repeatedly, to create complex, multi-valued xdr-format strings for passing to attribute.
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:
---------------------------------------
: xdrstring,num ( adr len number -- ) r xdrstring r xdrint xdr+ ; " size" 2000 xdrstring,num " vals" 3 xdrstring,num xdr+ 128 xdrint xdr+ 40 xdrint xdr+ 22 xdrint xdr+ " myprop" attribute ---------------------------------------
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 xdrbytes " idprom" attribute ----------------------------------------------
Convert an integer into an xdr-format string, suitable for passing as a "value" to attribute . For example:
----------------------------------
1152 xdrint " hres" attribute ----------------------------------
Convert a physical address (as a device space and a physical offset) into an xdr-format string suitable for attribute . For example:
---------------------------------------------
my-address 20.0000 + my-space xdrphys " resetloc" attribute ---------------------------------------------
Converts an ordinary string, such as created by " , into an xdr-format string suitable for attribute . For example:
-------------------------------------------
" MJS,SEH" xdrstring " authors" attribute -------------------------------------------
Decodes a number from the beginning of the property value array xdr1-adr xdr1-len , and returns the remainder of the property value array xdr2-adr xdr2-len and the number n.
For example:
---------------------------------------------------------
: show-clock-frequency ( -- ) " clock-frequency" get-inherited-attribute 0= if ." Clock frequency: " xdrtoint .h cr 2drop then ; ---------------------------------------------------------
Decodes a string from the beginning of the property value array xdr1-adr xdr1-len , and returns the remainder of the property value array xdr2-adr xdr2-len and the string adr3 len3 .
For example:
---------------------------------------------------------------------
: show-model ( -- ) " model" get-my-attribute 0= if xdrtostring type 2drop then ; ---------------------------------------------------------------------
n3 is the bit-by-bit exclusive-or of n1 with n2 .
Tokenizer instruction that truncates a 64-bit number to 32-bit .
Divides an unsigned 64-bit number by an unsigned 32-bit number, yields a 32- bit remainder and quotient