Innerhalb
Nach weiteren Dokumenten suchen
Support-Ressourcen
| Dieses Buch im PDF-Format herunterladen
Elements of FCode Programming
2
- FCode is based on the Forth-83 dialect of the Forth language, with the following major differences:
-
- The FCode tokenizer program uses normal textfiles, rather than the BLOCKs and block editing of Forth-83, and contains its own predefined words for file transfers.
- Forth-83 is designed for 16-bit machines. FCode is designed for 32-bit machines, so FCode handles 16 and 32-bit quantities differently than Forth- 83.
- FCode has these characteristics:
-
- The source format is machine and system independent.
- The binary format (FCode) is machine, system, and position independent.
- The binary format is compact.
- The binary format may be interpreted easily and efficiently.
- Programs are easy to develop and debug.
- The source format can easily be translated to binary format.
- The binary format can be untranslated back to a source format.
- Forth commands are called words, and are roughly analogous to procedures in other languages. Unlike other languages, such as C, which have operators and syntactic characters and procedures, in Forth every word is a procedure.
- Forth words consist of one to 31 printable characters, separated by one or more spaces from subsequent words.
- Forth uses a left-to-right reverse Polish notation, like some scientific calculators. The basic structure of Forth is: do this, now do that, now do something else, and so on.
- New Forth words are defined as sequences of previously existing words. Subsequently, new words may be used to create still more words.
- FCode is a byte-coded translation of a Forth program. Translating Forth source code to FCode involves replacing the Forth word names (stored as text strings) with their equivalent FCode numbers. The tokenized FCode takes up less space in PROM than the original ASCII textfile form of the Forth program from which it was derived.
- For purposes of this manual, the term FCode indicates both binary-coded FCode and the Forth programs written as ASCII text files for later conversion to binary-coded FCode.
- Except where a distinction between the two forms is explicitly stated, the use of FCode in this manual can be assumed to apply equally to both FCode and Forth.
Colon Definitions
- Two concepts are critical to understanding FCode (or Forth):
-
- A colon definition creates a new word with the same behavior of a sequence of existing words. A colon definition begins with a colon and ends with a semicolon.
- Most parameter passing is done through a pushdown, last-in, first-out stack.
- Normally, the action associated with an FCode word is performed when the FCode word is encountered. This is called interpret state. However, you can switch from interpret state to compile state.
- In interpret state, FCode words are executed as they are encountered. Interpret state operates until encountering a ":". The word ":" does the following:
-
- Allocates a new FCode word and associates it with the name immediately following the colon
- Switches to compile state
- During compile state operation, FCodes are saved for later execution, rather than being executed immediately. The sequence thus compiled is installed in the action tables as a new word, and can be later used in the same way as if it were a built-in word.
- Compile state continues until a ";" is read, switching operation back to interpret state.
- FCode words encountered after the colon are compiled into RAM for later use, until a semicolon is encountered. The word ";"does the following:
-
- Compiles an end-of-procedure FCode word
- Switches to interpret state
- After compilation, the newly-assigned FCode word can be either interpreted or compiled as part of yet another new word.
- If you define a new word having the same spelling as an existing word, the new definition supersedes the older one(s), but only for subsequent usages of that word.
- Here's an example of a colon definition, defining a new FCode word dac!:
-
: dac! ( data addr reg# -- ) swap dac ! dac + ! ;
Stack Operations
- Each FCode word is specified by its effect on the stack and any side effects, such as accessing memory. Most FCode words affect only the stack, by removing arguments from the stack, performing some operation on them, and putting the result or results back on the stack.
- The stack effects of an FCode word is described by a stack comment, included in the colon definition.
- In the previous example, the stack comment, beginning with "( " and ending with ")", shows that dac! takes three parameters from the stack, and doesn't replace them with anything when it's done.
- You can place stack comments anywhere in a colon definition, and you should include them anywhere that they will enhance clarity.
- The rightmost argument is on top of the stack, with any preceding arguments beneath it. In other words, arguments are pushed onto the stack in left to right order, leaving the most recent one (the rightmost one in the diagram) on the top.
- Following the stack comment in the preceding example are a series of words that describe the behavior of dac!. Executing dac! is the same as executing the list of words in its colon definition.
- Note that FCode words are separated by spaces, tabs, or newlines; "( data " is not the same as "(data ". Any visible character is part of a word, and not a separator.
- While case is not significant, by convention FCode is written in lower case.
Additional Information
- For more information about Forth programming, needed to use available FCode primitives, refer to the Forth-related books listed in "Related Books," on page xvi.
Programming Style
- Some people have described Forth as a write-only language. While it sometimes ends up that way, it is possible to write Forth (and FCode) programs that can be read and understood by more than just the original programmer.
Commenting Code
-
Comment code extravagantly, then consider adding more comments. The comments can help you and others maintain your code, and they don't add to the final size of the resulting FCode PROM.
- Typical practice is to use "( )" for stack comments and "\" for other descriptive text and comments.
Short Definitions
-
Keep word definitions short. If your definition exceeds half a page, try to break it up into two or more definitions. If it grows to a page or longer, you should break it up, if only to make the code easier to support in the future.
- A good size for a word definition is one or two lines of code.
Stack Comments
-
Always include stack comments in word definitions. It can be useful to compare intended function with what the code really does. Here's an example of a word definition with acceptable style.
-
\ xyz-map establishes a virtual-to-physical mapping for each of the
\ useful addressable regions on the board
: xyz-map ( -- )
\ Base-address Offset Size create-mapping
\ then save virtual address
my-address 40.0000 + 4 map-sbus ( virtaddr )
is status-register ( )
my-address 80.0000 + frame-buf-size map-sbus ( virtaddr )
is frame-buffer-adr ( )
;
|
- Stack items are generally written using descriptive names to help clarify correct usage. See the table below for stack item abbreviations used in this manual.
-
Table 2-1
| Notation | Description |
| | | Alternate stack results, for example: ( input -- adr len false | result true ). |
| ? | Unknown stack items (changed from ???). |
| ??? or [...] | Unknown stack items. |
| acf | Code field address. |
| adr | Memory address (generally a virtual address). |
| byte bxxx | 8-bit value (smallest byte in a 32-bit word). |
-
Table 2-1
| Notation | Description |
| char | 7-bit value (smallest byte), high bit unspecified. |
cnt
len
size | Count or length. |
| flag xxx? | 0 = false; any other value = true (usually -1). |
| long Lxxx | 32-bit value. |
| n n1 n2 n3 | Normal signed values (32-bit). |
| +n u | Unsigned, positive values (32-bit). |
| n[64]
(n.low n.hi)
| Extended-precision (64-bit) numbers (2 stack items). |
| phys | Physical address (actual hardware address). |
| pstr | Packed string (adr len means unpacked string). |
| virt | Virtual address (address used by software). |
| word wxxx | 16-bit value (smallest two bytes in a 32-bit word). |
A Minimum FCode Program
- If an SBus card is not needed during the boot process, a minimal FCode program that merely declares the name of the device will often suffice. Here is an example of an acceptable minimum program:
-
fcode-version1
" SUNW,bison" xdrstring " name" attribute
my-address h# 20.0000 +
my-space h# 100
" reg" attribute
end0
|
- This program creates a "name" property called "SUNW,bison" that will be used by the SunOS driver's identify routine to identify this device, and declares the location and size of on-board registers. The name that you use should always begin with your company name.
-
Note - To avoid name conflicts between different companies' products, use your company's public stock symbol.
- You can also use the following shorthand form. The FCode program generated will be equivalent to the minimum program given above.
-
fcode-version1
" SUNW,bison" name
my-address h# 20.0000 + my-space h# 100 reg
end0
|
- You might also want to include additional code to declare additional properties, create selftest routines, or to initialize the device after power-on.
FCode Classes
- There are four general classes of FCode source words:
-
-
Primitives. These words generally correspond directly to conventional Forth words, and implement functions such as addition, stack manipulation, and control structures.
-
System. These are extension words implemented in the boot PROMs, and implement functions such as memory allocation and device attribute reporting.
-
Interface. These are specific to particular types of devices, and implement functions such as draw-character.
-
Local. These are private words definitions, implemented and used by devices.
- Each FCode primitive is represented in the SBus card's PROM as a single byte. Other FCodes are represented in the SBus PROM as two consecutive bytes. The first byte, a value from 1 to 0xf, may be thought of as an escape code.
- One-byte FCode numbers range in value from 0x10 to 0xfe. Two-byte FCode numbers begin with a byte in the range 0x01 to 0x0f, and end with a byte in the range 0x00 to 0xff. The single-byte values 0x00 and 0xff signify "end of program" (either value will do; conventionally, 0x00 is used):
- Currently-defined FCodes are listed according to both functional groups and in numeric order in Appendix A, "FCode Reference".
Primitive FCodes
- There are more than 300 primitive FCode words, most of which exactly parallel Forth-83 words, divided into three groups:
-
- FCode words that generate a single FCode byte
-
tokenizer macros
-
tokenizer directives
- Primitive FCode words that have an exact parallel with standard Forth-83 words are given the same name as the equivalent Forth-83 word. Chapter 11, "FCode Dictionary", contains further descriptions of primitive FCodes.
- There are about another 70 tokenizer macros, most of which also have direct Forth-83 equivalents. These are convenient source code words translated by the tokenizer into short sequences of FCode primitives.
-
tokenizer directives are words that generate no FCodes, but are used to control the interpretation process. Cross-compiler directives include the words
-
-
binary, decimal, hex, and octal
-
b#, d#, h#, and o#
-
headers and headerless
-
\ and (
-
.(
-
alias
System FCodes
- System FCodes are used by all classes of FCode drivers for various system-related functions. System FCodes may be either service words or configuration words.
-
- Service words are available to the device's FCode driver when needed for functions such as memory mapping or diagnostic routines.
- Configuration words are included in the driver to document characteristics of the driver itself. These "properties" are passed up to the device's SunOS driver.
Interface FCodes
- Interface FCodes are standard routines used by the workstation's CPU to perform the functions of the SBus card's device. Different classes of devices will each use only the appropriate set of interface FCodes.
- For example, if the system wants to paint a character on the display screen, it does it by calling the interface FCode routine draw-character. This requires the frame buffer's FCode driver to assign its own definition into the draw-character interface word. It does this as follows
-
: my-draw ( char -- ) \ "local" word to draw a character.
... \ Definition contents.
; \ end of my-draw definition.
: my-install ( -- ) \ local word to install all interfaces.
...
['] my-draw is draw-character
...
;
|
- When my-install executes, draw-character has the behavior of my-draw.
Local FCodes
- Local FCodes are assigned, where needed, to words defined within the body of SBus driver code. There are over 2000 FCode byte values allocated for local FCodes. The byte values are meaningful only within the context of a particular driver. Different drivers reuse the same set of byte values.
|
|