An FCode source file is essentially a Forth language source code file. The basic Forth words available to the programmer are listed in Chapter 11, "FCode Dictionary".
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 19. fcode-version1 produces a header including the version1 FCode. The macro fcode-version2 is similar except that 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.
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 necessary in many cases but it is recommended since it allows some OpenBoot tools to recognize the file as a Forth source file.
The process of converting FCode source to FCode binary is referred to as tokenizing. A tokenizer program converts FCode source words to their corresponding byte-codes, as indicated in Chapter 11, "FCode Dictionary". A tokenizer program with instructions describing its use is available from SunExpress®. It is part of the SBus/SCSI Developer's Kit mentioned in the Preface.
An FCode program's source can reside in multiple files. The fload tokenizer directive directs the tokenizer input stream to load 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:
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 Test FCode Programs" on page 23.
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 SunExpress sets the load point to be the recommended 0x4000 address.
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, the end0 byte-code ------------------------------------------------
The format of the FCode header is:
Table 3-2
FCode Header Format
------------------------------------------------------------------------------------
Byte(s) Content ------------------------------------------------------------------------------------
0 One of the FCodes: version1, start0, start1, start2, 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 can 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 debug your FCode without having to create a PROM and attach it to your plug-in board for each FCode revision during the debug process. See the OpenBoot 3.x Command Reference for complete documentation of 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 (e.g. a driver which only publishes properties) then the program can be tested without installing the hardware.
Before powering-down the target machine to install the target hardware, a few NVRAM configuration variables 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
Setting
The start-up sequence in the machine's OpenBoot implementation normally examines all expansion buses for the presence of plug-in devices and their on- board FCode PROM programs. It then invokes the FCode evaluator to interpret any programs found. This process is called probing.
When using the Forth Monitor to load and interpret an FCode program in system memory, it is better to configure OpenBoot to avoid probing that device automatically. The probing can then be done manually (as explained later) from the Forth Monitor.
Configuring an OpenBoot implementation to avoid probing a given slot on a given expansion bus can be done in various implementation-dependent ways. That is, they will be different for different systems and different expansion buses.
Many machines with a SBus have an NVRAM configuration variable named sbus-probe-list. It defines which SBus card slots will be probed during start up and the order in which they will be probed.
For example, a machine with four SBus slots might have the sbus-probe-list configuration variable set to a default value of 0123. Setting sbus-probe-list to 013 directs OpenBoot during start-up to probe first SBus slots 0, 1, and 3. This leaves SBus slot 2 un-probed, free for use by the device under development.
Methods to prevent probing a given slot for other types of expansion buses can involve using the NVRAMRC script. Among other uses, an NVRAMRC script can:
After the FCode program is debugged and programmed in PROM on the device, you can do a full system test (including automatic probing of the new device), by restoring the expansion bus probing configuration to the default.
After completing the configuration described above, power the machine down and install the device. Then power the system up. The display should stop scrolling at the ok prompt, ready to accept Forth Monitor commands.
Note - On the SPARCstation(TM) 1 and SPARCstation 1+, SBus slot 3 may be used only for SBus slave devices, such as frame buffers. Unlike slots 1 and 2, it may not be used for SBus master devices, such as disk drive or network interfaces.
Refer to the OpenBoot 3.x Command Reference for a list and description of the line-editing commands available with the Forth Monitor.
Complete directions for using the Forth Monitor to download files to system memory are provided in the OpenBoot 3.x Command Reference. A synopsis of FCode words for executing FCode source files is shown below.
Table 3-3
File Execute-related Commands
--------------------------------------------------------------------------------------------------------------------
FCode Stack Notation Function --------------------------------------------------------------------------------------------------------------------
begin-package ( arg-addr arg-len reg-addr reg-len path-addr path-len -- ) Initializes device tree for executing FCode. end-package ( -- ) Completes a device tree entry and returns to the Forth Monitor environment. open-dev ( path-addr path-len -- ) Opens the specified device node and all of its parents. device-end ( -- ) Closes the current node and returns to the Forth Monitor environment. select-dev ( path-addr path-len -- ) Opens the specified device node and all of its parents, and makes the device the current instance. unselect-dev ( -- ) Closes the specified device node and all of its parents, and unselects the active package and current instance leaving none selected. set-args ( arg-addr arg-len reg-addr reg-len -- ) Sets values returned by my-args, my-space and my-address for the current node. execute-device-method ( ... path-addr path-len cmd-addr cmd-len -- ... ok? ) Executes the named command in the specified device tree node. --------------------------------------------------------------------------------------------------------------------
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 SunExpress 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 3.x 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 3.x 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 3.x 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 SunExpress, 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.
Forth programs loaded with dl must be ASCII files.
To load the file over the serial line, connect the system's serial port A to a machine that is able to transfer a file on request. One method is to set up a TIP window on another Sun system. (See OpenBoot 3.x Command Reference for information on this procedure.) The following example assumes a TIP window setup.
-------------
ok dl -------------
-------------------------------------
~C (local command) cat filename (Away two seconds) ^-D -------------------------------------
The ok prompt appears on the screen of the system to which the file is loaded.
dl normally loads the file at 4000 (hex). The file is automatically interpreted after it is loaded.
FCode program interpretation involves creating a device node on the device tree. Device nodes are also known as packages. Creating a device node from downloaded FCode involves the following steps:
For example, a
-------------------------------------------
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, parent nodes, which support child nodes, can be used as this
argument to
In the example, the string, " 3,0" indicates the SBus slot number, 3 and byte-offset 0 in 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 in the FCode program with both
the my-address
In the preceding example, the initial 0 0 represents a null argument string passed to the FCode program.
This argument string is retrieved in the FCode program with the my-args
begin-package
----------------------------------------------------------------------------
: begin-package ( arg-addr arg-len reg-addr reg-len dev-addr dev-len -- ) select-dev new-device set-args ; ----------------------------------------------------------------------------
select-dev
For FCode programs downloaded with
----------------------------
ok load-base ' c@ byte-load ----------------------------
load-base is the system default load address. The argument, ' c@ , tells
-----------------
ok end-package -----------------
It is defined as:
-------------------------------------------------------
: end-package ( -- ) finish-device unselect-dev ; -------------------------------------------------------
unselect-dev
The Forth Monitor has many built-in commands to navigate the device tree. Table 3-4 lists the Forth Monitor commands supporting device node browsing:
Table 3-4
Commands for Browsing the Device Tree
----------------------------------------------------------------------------------------------------------------
Command Description ----------------------------------------------------------------------------------------------------------------
.properties Display the names and values of the current node's properties. dev device-path Choose the indicated device node, making it the current node. dev node-name Search for a node with the given name in the sub-tree below the current node, and choose the first such node found. dev .. Choose the device node that is the parent of the current node. dev / Choose the root machine node. device-end De-select the current device node, leaving no node selected. " device-path" find-device Choose device node, similar to dev. get-inherited-property ( name-addr name-len -- true | value-addr value-len false ) Return property value of current instance or its parents get-my-property ( name-addr name-len -- true | value-addr value-len false ) Return property value of current instance. ls Display the names of the current node's children. pwd Display the device path name that names the current node. see wordname Decompile the specified word. 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 can use the Forth Monitor to browse the node. See the OpenBoot 3.x Command Reference for a more complete discussion. Here is a brief synopsis of the available commands:
-----------------------------
ok dev /sbus/ACME,widget -----------------------------
----------------------------------------
ok " /sbus/ACME,widget" find-device ----------------------------------------
The Forth Monitor provides the capability to test the methods of an FCode program by allowing you to execute individual methods from the Forth Monitor prompt.
select-dev
---------------------------------------
ok " /sbus/ACME,widget" select-dev ---------------------------------------
select-dev
Once these steps are performed you can execute the methods of the current device node by typing their names at the prompt. For example:
-----------------------------
ok clear-widget-register ok fetch-widget-register . 0 -----------------------------
As is generally true of the Forth language, if execution of a method exposes an
error in the code, the error can be isolated by executing the component words
of the method step-by-step. Use see
-------------------------------
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 can 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
This process is also enhanced by executing showstack
---------------------
ok 1 2 ok showstack 1 2 ok . clear 3 4 2 3 4 ok ---------------------
Device nodes can also be modified as needed with any of the following techniques:
---------------------------------------------------
ok : open open initialize-widget-register-2 ; ---------------------------------------------------
In general, such redefinitions affect only external uses of the named method (i.e. calls from other packages via $call-method and the like) and interactive use via the Forth Monitor. Previously compiled calls to the method in the same package are unaffected unless the method is called by name (e.g. with $call-self).
unselect-dev
--------------------
ok unselect-dev --------------------
Sometimes, select-dev will not work because the open method of a newly- written package does not work correctly. In this case, begin-select-dev can be used since it does everything that select-dev does except for opening the last child node. For example:
---------------------------------------------
ok " /sbus/ACME,widget" begin-select-dev ---------------------------------------------
execute-device-method
-------------------------------------------------------------
ok " /sbus/ACME,widget" " test-it" execute-device-method -------------------------------------------------------------
execute-device-method
execute-device-method
Note that, in contrast to select-dev
In summary, execute-device-method
apply
---------------------------------------
ok apply test-it /sbus/ACME,widget ---------------------------------------
Since apply
The Forth Monitor enables you to skip the tokenizer and download FCode program source directly. This practice is not recommended since the only advantage is to save a small amount of time tokenizing the program. There are also some disadvantages:
To load an ASCII Forth source file over serial line A, you use the command dl
The output of the tokenizer program is used to make an actual FCode PROM. If your PROM burning tools do not accept the raw binary format of the tokenizer, you may need to develop a format conversion utility.
You can either let OpenBoot automatically evaluate the FCode program from the PROM or you can remove the device from the OpenBoot probing as discussed earlier in "Configuring the Target Machine" on page 21.
The same process discussed for testing FCode programs loaded to system memory can 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 can be built manually as in the following example for a device installed in SBus slot 1:
-----------------------------------------------------------
ok 10000 constant rom-size ok " /sbus" select-dev ok " 1" decode-unit ( phys.lo phys.mid phys.hi ) ok rom-size map-in ( virt ) ok new-device ( virt ) ok " " " 1,0" set-args ( virt ) ok dup 1 byte-load ( virt ) ok finish-device ( virt ) 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 you must map in and map out the FCode
PROM by using the decode-unit
You can browse the device node and exercise the device methods in the same way as described earlier. You can also define new methods and patch existing ones. Of course, these modifications will only remain until a system reset.