An FCode source file is essentially a Forth language source code file. The basic Forth words available to the programmer are listed in the FCode Dictionary chapter of this manual. Typically Forth source files are named with a .fth suffix. FCode source files follow the same convention.
FCode programs have the following format:
--------------------------------------------------
\ Title comment describing the program that follows fcode-version1 < body of the FCode program '> end0 --------------------------------------------------
fcode-version1 is a macro which directs the tokenizer to create an FCode header. For a description of the FCode header see "FCode Binary Format" on page 17. fcode-version1 produces a header including the version1 FCode. The macro fcode-version2 is similar except it produces a header containing the start1 FCode. This macro may also be used to begin the FCode source. However since OpenBoot version 1 systems only recognize version1, plug-in device FCode that must run in OpenBoot version 1 systems must use fcode-version1.
See Appendix D, "Changes in OpenBoot 1 FCode Usage" for more information on differences between version 1 and version 2 FCode usage.
end0 is an FCode that marks the end of an FCode program. It must be at the end of the program or erroneous results may occur. end1 is an alternative but end0 is recommended.
The comment in the first line is not strictly necessary in many cases but it is recommended since some OpenBoot tools require it.
The process of converting FCode source to FCode binary is referred to as tokenizing. A tokenizer program coverts FCode source words to their corresponding byte-codes, as indicated in the FCode Dictionary chapter. A tokenizer program together with instructions describing its use is available from the Sun SBus Support Group.
An FCode program's source may reside across multiple files. The fload tokenizer directive may be used to direct the tokenizer input stream to another file. fload acts like an #include statement in C. When fload is encountered the tokenizer begins processing the file named by the fload directive. When the named file is completed, tokenizing continues with the file that issued the fload. fload directives may be nested.
Typically, the tokenizer produces a file in the following format based on the
UNIX
The header has the following format:
You can use this file to load either an FCode PROM or system memory for debugging as described in "Using the Forth Monitor to Download FCode" on page 20.
The load point of the file is not used when burning an FCode PROM, but is used by Forth Monitor commands that load FCode files into system memory. The tokenizer available from the SBus Support Group sets the load point to be the recommended 0x4000 address.
By convention, the file output by the tokenizer has the suffix .fcode.
The format of FCode binary that is required by the OpenBoot FCode evaluator is as follows:
Table 3-1 FCode Binary Format
------------------------------------------------------------
Element Structure ------------------------------------------------------------
FCode header eight bytes Body 0 or more bytes End byte-code 1 byte either the end0 or end1 byte-code ------------------------------------------------------------
The format of the FCode header is:
Table 3-2 FCode Header Format
---------------------------------------------------------------------------
Byte(s) Content ---------------------------------------------------------------------------
0 One of the FCodes: version1,start1,start2,start3,start4 1 reserved 2 and 3 16-bit checksum of the FCode body 4 through 7 count of bytes in the FCode binary image including the header ---------------------------------------------------------------------------
Once you have created the FCode binary you may test it using the OpenBoot Forth Monitor. The Forth Monitor provides facilities to allow you to load your program into system memory and direct the FCode evaluator to interpret it from there. This allows you to avoid having to burn a PROM and attach it to your plug-in board with each FCode revision during the debug process. See the OpenBoot Command Reference for complete documentation on the use of the Forth Monitor.
The FCode testing process generally involves the following steps:
If the FCode program does not include any methods which involve using the actual hardware then the program may be tested without installing the hardware.
Before powering-down the target machine to install the target hardware, a few NVRAM parameters should be set to appropriate values. You can set them from the Forth Monitor as follows:
------------------------------------
ok setenv auto-boot? false ok setenv fcode-debug? true ------------------------------------
Setting auto-boot? to false tells OpenBoot not to boot the OS upon a machine reset but rather to enter the Forth Monitor at the ok prompt.
Setting fcode-debug? to true tells the OpenBoot FCode evaluator to save the names of words created by interpreting FCode words which were tokenized with headers on. This is in addition to words defined with external on - whose names are always saved. fcode-debug? defaults to false to conserve RAM space in normal machine operation. With the names saved, the debugging methods described in later sections will be easier since it will be easier to read decompiled FCode.
The start-up sequence in the machine's OpenBoot implementation will be programmed to examine all expansion buses at well-known locations for the presence of plug-in devices and their onboard FCode PROM program. It then invokes the FCode evaluator to interpret the program. This process is called probing the device.
When using the Forth Monitor to load and interpret an FCode program in system memory, it is better to configure OpenBoot to not automatically try to probe the device. The probing will be done manually (as explained later) from the Forth Monitor after the FCode program is loaded into memory.
Configuring an OpenBoot implementation not to probe a given slot on a given expansion bus may be done in various ways which are implementation dependent. That is, they will be different for different systems and different expansion buses.
Many machines have an NVRAM parameter called sbus-probe-list which defines which SBus card slots will be probed during start up and the order in which they will be probed.
For example, on the SPARCstation2, sbus-probe-list has a default value of 0123. Setting sbus-probe-list to 013 directs OpenBoot during start-up to probe first SBus slots 0 (built-in devices), then slot 1, and finally slot 3. This leaves SBus slot 2 unprobed, free for use by the device under development.
Methods to prevent probing a given slot for other types of expansion buses may involve using the nvramrc. An nvramrc script could be used to patch an implementation specific OpenBoot word which defines the bus's probe sequence or to modify a property of the expansion buses device node which describes the sequence.
After the FCode program is debugged and programmed in PROM on the device and you want to do a full system test (including automatic probing of the new device), restore the expansion bus probing configuration to the default.
After completing the configuration described above, power-down the machine and install the device. Then power-up the system and it should stop at the ok prompt ready for Forth Monitor commands.
Note - On the SPARCstation1 and SPARCstation1+, SBus slot 3 may be used only for SBus slave devices, such as framebuffers. Unlike slots 1 and 2, it may not be used for SBus master devices, such as disk drive or network interfaces.
Complete directions for using the Forth Monitor to download files to system memory are provided in the OpenBoot Command Reference. This chapter contains a synopsis for FCode program files. FCode words used to help download and execute FCode source files are shown below.
Table 3-3 File Download/Execute-related Toolkit Commands
-------------------------------------------------------------------------------------------------------------------------
FCode Stack Notation Function -------------------------------------------------------------------------------------------------------------------------
begin-package ( arg-adr arg-len reg-adr reg-len path-adr path-len -- ) Initialize device tree for executing FCode. select-dev ( path-adr path-len -- ) Open specified device node and make it the current node. set-args ( arg-adr arg-len reg-adr reg-len -- ) Sets values returned by my-args, my-space and my-address for the current node. end-package ( -- ) Complete device tree entry and return to Forth Monitor environment. unselect-dev ( -- ) Closes current node and return to Forth Monitor environment. new-slot-node ( -- ) Prepare device tree for new entry. (1.x only) execute- ( ... path-adr path-len cmd-adr cmd-len -- ... ok? ) Execute named command within the device-method specified device tree node. probe-slot ( slot# -- ) Setup and execute FCode in the given SBus (1.x only) slot. -------------------------------------------------------------------------------------------------------------------------
dload loads files over Ethernet at a specified address, as shown below.
-----------------------------
ok 4000 dload filename -----------------------------
In the above example, filename must be relative to the server's root. Use 4000 (hex) as the address for dload input.
FCode programs loaded with dload must be in the format described in "Tokenizing FCode Source". The tokenizer provided by the SBus Support Group can output these files.
dload uses the trivial file transfer protocol (TFTP), so the server may need to have its permissions adjusted for this to work.
dlbin may be used to load files over serial line A. Connect the target system's serial port A to a machine that is able to transfer a file on request. The following example assumes a tip window setup on a Sun system which will provide the FCode file. (See the OpenBoot Command Reference for information on setting tip connections.)
-------------
ok dlbin -------------
---------------------------------------
~C (local command) cat filename (Away two seconds) ---------------------------------------
The ok prompt will reappear on the screen of the target system.
FCode programs loaded with dlbin must be in the format described in "Tokenizing FCode Source". dlbin loads the files at the entry point indicated in the file header. It is recommended that this address be 0x4000.
You can also load an FCode program with boot, the command normally used to boot the operating system. Use the following format:
-------------------------------------------------------
ok boot [device-specifier] [filename] -h -------------------------------------------------------
device-specifier is either a full device path name or a device alias. See the OpenBoot Command Reference for information on device path names and aliases.
For a hard disk or floppy partition, filename is relative to the resident file system. See the OpenBoot Command Reference for information on creating a bootable floppy disk. For a network, filename is relative to the system's root partition on its root server. In both cases, the leading / must be omitted from the file path.
The -h flag specifies that the program should be loaded, but not executed. This flag must be included since otherwise boot will attempt to automatically execute the file assuming it is executable binary.
boot uses intermediate booters to accomplish its task. When loading from a hard disk or floppy disk, the OpenBoot firmware first loads the disk's boot block, which in turn loads a second-level booter. When loading over a network, the firmware uses TFTP to load the second-level booter. In both cases, filename and -h are passed to these intermediate booters.
The output file produced by a tokenizer may need to be converted to the format required by the secondary boot program. For example, Solaris 2.x intermediate booters require ELF format. fakeboot, a program available from the Sun SBus Support Group, may be useful in this process.
The location in memory where the FCode program is loaded depends on the secondary boot program and the fakeboot program.
FCode program interpretation involves creating a device node on the device tree.
There are some basic differences between the device tree of version 2 and of version 1. Improvements were made in version 2 that involve the form of physical addresses associated with device nodes and the ability to include device driver methods in device nodes. Thus use of the FCode evaluator to interpret an FCode Program differs for OpenBoot version 2 and OpenBoot version 1 systems.
For version 2, device nodes are also known as packages. Creating a device node from downloaded FCode involves the following steps:
For example, a begin-package call for creating a device node for an SBus card installed in slot #3 of a SPARCstation2 looks like:
---------------------------------------
ok 0 0 " 3,0" " /sbus" begin-package ---------------------------------------
In the example, the string, /sbus, indicates that the device node which will be created by the FCode program is to be a child node of the /sbus node in the device tree.
In general, any device node which supports child nodes - called parent nodes - may be used as this argument to begin-package. The device node defined by the FCode program will be made a child of that node. The full device pathname from the root node must be given. Another example of an SBus parent node is on a SPARCstation10 where its device pathname is /iommu/sbus.
In the example, the string, "3,0" indicates the SBus slot number, 3, and byte- offset, 0, within the slot's address space where the device node is to be based.
In general, this string is a pair of values separated by a comma which identify the physical address associated with the expansion slot. The form of this physical address depends on the physical address space defined by the parent node. For children of an SBus node, the form is slot-number,byte-offset. Other parent nodes will define different address spaces.
The physical address pair value is retrieved within the FCode program with both the my-address and my-space FCodes.
In the example, the initial 0 0 represents a null argument string passed to the FCode program.
This argument string is retrieved within the FCode program with the my-args FCode. Generally, FCode programs do not take arguments at interpretation time so this will usually be the null string. (For the SPARCstation2, when the FCode PROM on an SBus card is automatically interpreted during system power-on, this is set to a null string).
begin-package is defined as:
---------------------------------------------------
: begin-package select-dev new-device set-args ; ---------------------------------------------------
select-dev ( adr len -- ) - Opens the input device node (the parent node) and makes it the current instance.
new-device ( -- ) - Initializes a new device node as a child of the currently active node and makes it the current instance.
set-args ( arg-adr arg-len reg-adr reg-len -- ) - Sets the values returned by my-args, my-space, and my-address for the current instance.
byte-load is the Forth Monitor command that invokes the FCode evaluator to compile the FCode program into the current instance.
For FCode programs downloaded with dload or dlbin use:
----------------------
ok 4000 1 byte-load ----------------------
4000 is the load address recommended to be used as input to dload and as the entry point in the file loaded by dlbin. The argument, 1, is the byte spacing between FCode byte-codes which byte-load is to expect. For FCode loaded into memory this is always 1.
For FCode programs downloaded with boot, the address at which the FCode is loaded depends on the second level booter and the program that is used to convert the FCode file to a format accepted by the booter, such as fakeboot. For example, if the file is loaded with the FCode binary starting at 4030 use:
----------------------
ok 4030 1 byte-load ----------------------
end-package finishes up the creation of the device tree node.
-----------------
ok end-package -----------------
It is defined as:
--------------------------------------------
: end-package finish-device unselect-dev ; --------------------------------------------
finish-device ( -- ) Completes the device tree node initialized by new- device and changes the current instance to be the parent node.
unselect-dev (-- ) Closes the parent device tree node and returns to the normal Forth Monitor environment. That is, there is no longer a current instance or active package.
OpenBoot Version 1 was only implemented in early SPARCstations which only contain the SBus expansion bus. Thus the following discussion assumes an FCode program for an SBus plug-in device on early SPARCstations.
In version 1, the user sets only the value of my-address. Unlike version 2, my-address is defined as the offset - from the base of the SBus in the systems root address space - of the SBus slot in which the device is installed.
Set my-address as in the following example for SBus slot 1:
----------------------------
ok 200.0000 is my-address ----------------------------
Hexadecimal slot offsets for the SPARCstation1/1+, SPARCstation IPC and SPARCstation 1E are:
In version 1 the user prepares the device tree for a new entry by issuing the new-slot-node command. This command assumes that the new device will be the child of the SBus nexus node in the slot indicated by my-address.
-------------------
ok new-slot-node -------------------
new-slot-node is not in OpenBoot versions 1.0 or 1.1, but you can download it with the reheader.fth file available from the Sun SBus Support Group, or enter the following patch directly:
-------------------------------
\ For OpenBoot version 1.0 : new-slot-node ( -- ) ffe9b192 execute my-address ffe93da0 execute slot# ffe9bd6e execute ; \ For OpenBoot version 1.1 : new-slot-node ( -- ) ffe9b152 execute my-address ffe9499c execute slot# ffe9bd56 execute ; -------------------------------
For version 1, use byte-load to interpret the FCode program as described for version 2.
The capability to view device nodes as well as what is contained in device nodes is different in OpenBoot versions 1 and 2. In version 2, the Forth Monitor has built-in many more commands to navigate the device tree.
Table 3-4 lists available OpenBoot commands supporting device node browsing:
Table 3-4 Commands for Browsing the Device Tree
----------------------------------------------------------------------------------------------------------------------
Command Description ----------------------------------------------------------------------------------------------------------------------
.attributes Display the names and values of the current node's properties. cd device-path Select the indicated device node, making it the current node. cd node-name Search for a node with the given name in the subtree below the current node, and select the first such node found. cd .. Select the device node that is the parent of the current node. cd / Select the root machine node. device-end De-select the current device node, leaving no node selected. find-device ( path-adr path-len -- ) Select device node, like cd. get-attribute ( name-adr name-len -- true | value-adr value-len false ) Returns property value. ls Display the names of the current node's children. pwd Display the device path name that names the current node. show-devs [device-path] Display all the devices known to the system directly beneath a given level in the device hierarchy. show-devs used by itself shows the entire device tree. words Display the names of the current node's methods. ----------------------------------------------------------------------------------------------------------------------
Once a device node has been created, you may use the Forth Monitor to browse the node. See the OpenBoot Command Reference for a more complete discussion on this. Below is a brief synopsis of the available commands.
--------------------------
ok cd /sbus/ACME,widget --------------------------
--------------------------------------
ok " /sbus/ACME,widget" find-device --------------------------------------
For version 1, only device node properties are included in device nodes and there are no commands built in the Forth Monitor to view them. Here is some Forth code which may be loaded into a version 1 system to view device nodes and their properties. It defines the command,.dev, with the following usage:
-----------------------------------------------------------------------------
\ Forth program to display device node properties 3 /l* constant /prop : printable? ( char -- flag ) bl h# 7e between ; : .cstring ( adr -- ) begin dup c@ dup while emit 1+ repeat 2drop ; : xtype ( adr len -- ) bounds ?do i c@ dup printable? if emit else drop then loop ; : xdump ( adr len -- ) bounds ?do i unaligned-@ .h /l +loop ; : to-column ( column# -- ) #out @ - 1 max spaces ; : .props ( prop-adr -- ) begin dup l@ while dup l@ .cstring dup la1+ l@ over 2 la+ l@ swap d# 16 to-column 2dup xtype d# 32 to-column xdump cr /prop + repeat drop ; : .dev ( adr -- [ next-adr' ] [ child-adr ] ) ." Node at: " dup .h cr dup 2 la+ l@ ?dup if .props then dup r l@ ?dup if ." Next: " dup .h then r la1+ l@ ?dup if ." Child: " dup .h then cr ; ok root-info .dev (displays root node) ok .dev (displays next node) ok .dev -----------------------------------------------------------------------------
The Forth Monitor provides the capability to test the device node driver methods of an FCode program by allowing the user to execute individual methods from the Forth Monitor prompt.
OpenBoot version 2 has much more robust support for device node methods than version 1. In version 2, there are basically two ways to invoke device node methods. They are described below. For version 1 considerations see the third part of this section.
For example, on a SPARCstation2 execute this command as follows:
--------------------------------------
ok " /sbus/ACME,widget" select-dev --------------------------------------
select-dev performs the following:
Once these steps are performed the current device node methods may be executed by simply typing their name at the prompt. For example:
-----------------------------
ok clear-widget-register ok fetch-widget-register . 0 ok -----------------------------
As is generally true of the Forth language, if execution of the method exposes an error in the code, the error may be isolated by executing the component words of the method step-by-step. Use see to decompile the method. And then type the component words individually until the error is evident. For example:
-------------------------------
ok see clear-widget-register : clear-widget-register enable-register-write 0 widget-register rl! disable-register-write ; ok enable-register-write ok 0 widget-register rl! ok disable-register-write -------------------------------
This process may be performed recursively by decompiling the component words and then individually executing their component words. This is much easier if most of the words were defined with the headers directive. Use showstack to enable automatic printing of the Forth stack after the execution of each step to ensure correct stack behavior.
Device nodes may also be modified "on-the-fly" by any of the following:
--------------------------------------------------
ok : open open initialize-widget-register-2 ; --------------------------------------------------
Of course these modifications only stay in effect until the machine is reset and once they are working you'll probably want to include the modifications to the FCode program source.
unselect-dev reverses the effects of select-dev by calling the close method of each device in the path of the current active node, destroying the package instance of each node, and returning to the normal Forth Monitor environment. Execute unselect-dev as follows:
------------------
ok unselect-dev ------------------
-----------------------------------------------------------
ok " /sbus/ACME,widget" " test-it" execute-device-method -----------------------------------------------------------
execute-device-method returns true if it successfully executes the method; false, if not.
execute-device-method performs the following steps before invoking the method:
Note that the last item in the above list is a significant departure from how select-dev works. Since the device open method is not executed, any method invoked in this manner must be able to stand alone - not requiring any preestablished state which normally is created by open.
In summary, execute-device-method is provided to allow execution of device node methods which have been designed to provide their own state initialization and therefore to execute without previous execution of the open method. A typical example is a selftest method.
With the exception of framebuffer device drivers, it not recommended to make use of device node methods in version 1. Since booting from plug-in boards is not supported in version 1 the only beneficial methods would be for device diagnostics.
Some reasons to avoid device methods in version 1 are:
The Forth Monitor provides the capability to skip the tokenizer and download FCode program source directly. This practice is not recommended since there is not much advantage to this except to save a small amount of time tokenizing the program. And, in fact, there are some down sides:
To load an ASCII Forth source file over serial line A you use the command, dl. In addition to loading the file over the serial line it compiles the Forth source while it is loading without requiring a extra command. Therefore the developer must execute begin-package before downloading. See the OpenBoot Command Reference for details on the use of dl.
To load a program over a network with dload or from a disk with boot
follow the instructions in the OpenBoot Command Reference. These commands do
not evaluate the Forth source so downloading may be done before begin-
package. dload requires that the source file begin with the two characters,
"\ " (backslash space).
For OpenBoot version 1, using source code directly may cause problems since some FCode words do not have name headers and will thus be unrecognized. A file named reheader.fth, available from the Sun SBus Support Group, may be downloaded and executed to provide the missing words.
The output of the tokenizer program is used to make an actual FCode PROM. If your PROM burning tools do not accept the format, you may need to develop a format conversion utility.
You may either let OpenBoot automatically evaluate the FCode program from the PROM or you may remove the device from the OpenBoot probing as discussed earlier in "Configuring the Target Machine".
The same process discussed for testing FCode programs which are loaded to system memory may be used to test FCode programs already loaded into PROM on the device.
If you take the device out of the probing sequence, a device node may be built manually as in the following example for a SPARCstation2 with the device installed in SBus slot 1:
---------------------------------------------------------
ok 10000 constant rom-size ok " /sbus" select-dev ok " 1,0" decode-unit ( offset space ) ok rom-size map-in ( fcode-vadr ) ok new-device ( fcode-vadr ) ok " " " 1,0" set-args ( fcode-vadr ) ok dup 1 byte-load ( fcode-vadr ) ok finish-device ( fcode-vadr ) ok rom-size map-out ok unselect-dev ---------------------------------------------------------
This is essentially the same sequence as outlined for evaluating FCode loaded into system memory except that the user must map in and map out the FCode PROM by using the decode-unit and use the map-in and map-out methods of the parent device node. For more information about these methods, see Chapter 8, "Hierarchical Devices".
You may browse the device node and exercise the device methods in the same way as described earlier. You may also define new methods and patch existing ones. Of course these modifications will only remain until a system reset.
If you take the device out of the probing sequence, a device node may be built manually as in the following example with the device installed in SBus slot 2:
-------------------
ok 2 probe-slot -------------------
In this case, probe-slot is equivalent to:
--------------------------------------------------
ok 400.0000 is my-address ok new-slot-node ok my-address 10000 map-sbus ( fcode-vadr) ok dup 1 byte-load ( fcode-vadr ) ok 10000 free-virtual --------------------------------------------------