Each operation in the binary Fasload language is an eight-bit
(one-byte) opcode. Each has a name beginning with "FOP-
". In
the following descriptions, the name is followed by operand
descriptors. Each descriptor denotes operands that follow the opcode
in the input stream. A quantity in parentheses indicates the number
of bytes of data from the stream making up the operand. Operands
which implicitly come from the stack are noted in the text. The
notation "→ stack" means that the result is pushed onto the
stack; "→ table" similarly means that the result is added to the
table. A construction like "n(1) value(n)" means that
first a single byte n is read from the input stream, and this
byte specifies how many bytes to read as the operand named value.
All numeric values are unsigned binary integers unless otherwise
specified. Values described as "signed" are in two’s-complement form
unless otherwise specified. When an integer read from the stream
occupies more than one byte, the first byte read is the least
significant byte, and the last byte read is the most significant (and
contains the sign bit as its high-order bit if the entire integer is
signed).
Some of the operations are not necessary, but are rather special cases of or combinations of others. These are included to reduce the size of the file or to speed up important cases. As an example, nearly all strings are less than 256 bytes long, and so a special form of string operation might take a one-byte length rather than a four-byte length. As another example, some implementations may choose to store bits in an array in a left-to-right format within each word, rather than right-to-left. The Fasload file format may support both formats, with one being significantly more efficient than the other for a given implementation. The compiler for any implementation may generate the more efficient form for that implementation, and yet compatibility can be maintained by requiring all implementations to support both formats in Fasload files.
Measurements are to be made to determine which operation codes are worthwhile; little-used operations may be discarded and new ones added. After a point the definition will be "frozen", meaning that existing operations may not be deleted (though new ones may be added; some operations codes will be reserved for that purpose).
FOP-NOP
No operation. (This is included because it is recognized that some implementations may benefit from alignment of operands to some operations, for example to 32-bit boundaries. This operation can be used to pad the instruction stream to a desired boundary.)
FOP-POP
→ tableOne item is popped from the stack and added to the table.
FOP-PUSH
index(4) → stackItem number index of the table is pushed onto the stack. The first element of the table is item number zero.
FOP-BYTE-PUSH
index(1) → stackItem number index of the table is pushed onto the stack. The first element of the table is item number zero.
FOP-EMPTY-LIST
→ stackThe empty list (()
) is pushed onto the stack.
FOP-TRUTH
→ stackThe standard truth value (T
) is pushed onto the stack.
6 FOP-SYMBOL-SAVE
n(4) name(n)
The four-byte operand n specifies the length of the print name of a symbol. The name follows, one character per byte, with the first byte of the print name being the first read. The name is interned in the default package, and the resulting symbol is both pushed onto the stack and added to the table.
FOP-SMALL-SYMBOL-SAVE
n(1) name(n) → stack & tableThe one-byte operand n specifies the length of the print name of a symbol. The name follows, one character per byte, with the first byte of the print name being the first read. The name is interned in the default package, and the resulting symbol is both pushed onto the stack and added to the table.
FOP-SYMBOL-IN-PACKAGE-SAVE
index(4) n(4) name(n) → stack & tableThe four-byte index specifies a package stored in the table. The four-byte operand n specifies the length of the print name of a symbol. The name follows, one character per byte, with the first byte of the print name being the first read. The name is interned in the specified package, and the resulting symbol is both pushed onto the stack and added to the table.
FOP-SMALL-SYMBOL-IN-PACKAGE-SAVE
index(4) n(1) name(n) → stack & tableThe four-byte index specifies a package stored in the table. The one-byte operand n specifies the length of the print name of a symbol. The name follows, one character per byte, with the first byte of the print name being the first read. The name is interned in the specified package, and the resulting symbol is both pushed onto the stack and added to the table.
FOP-SYMBOL-IN-BYTE-PACKAGE-SAVE
index(1) n(4) name(n) → stack & tableThe one-byte index specifies a package stored in the table. The four-byte operand n specifies the length of the print name of a symbol. The name follows, one character per byte, with the first byte of the print name being the first read. The name is interned in the specified package, and the resulting symbol is both pushed onto the stack and added to the table.
FOP-SMALL-SYMBOL-IN-BYTE-PACKAGE-SAVE
index(1) n(1) name(n) → stack & tableThe one-byte index specifies a package stored in the table. The one-byte operand n specifies the length of the print name of a symbol. The name follows, one character per byte, with the first byte of the print name being the first read. The name is interned in the specified package, and the resulting symbol is both pushed onto the stack and added to the table.
FOP-DEFAULT-PACKAGE
index(4)A package stored in the table entry specified by index is made
the default package for future FOP-SYMBOL
and FOP-SMALL-SYMBOL
interning operations. (These package FOPs may change or disappear
as the package system is determined.)
FOP-PACKAGE
→ tableAn item is popped from the stack; it must be a symbol. The package of that name is located and pushed onto the table.
FOP-LIST
length(1) → stackThe unsigned operand length specifies a number of
operands to be popped from the stack. These are made into a list
of that length, and the list is pushed onto the stack.
The first item popped from the stack becomes the last element of
the list, and so on. Hence an iterative loop can start with
the empty list and perform "pop an item and cons it onto the list"
length times.
(Lists of length greater than 255 can be made by using FOP-LIST*
repeatedly.)
FOP-LIST*
length(1) → stackThis is like FOP-LIST
except that the constructed list is terminated
not by ()
(the empty list), but by an item popped from the stack
before any others are. Therefore length+1 items are popped in all.
Hence an iterative loop can start with
a popped item and perform "pop an item and cons it onto the list"
length+1 times.
FOP-LIST-1
, FOP-LIST-2
, ..., FOP-LIST-8
FOP-LIST-k
is like FOP-LIST
with a byte containing k
following it. These exist purely to reduce the size of Fasload files.
Measurements need to be made to determine the useful values of k.
FOP-LIST*-1
, FOP-LIST*-2
, ..., FOP-LIST*-8
FOP-LIST*-k
is like FOP-LIST*
with a byte containing k
following it. These exist purely to reduce the size of Fasload files.
Measurements need to be made to determine the useful values of k.
FOP-INTEGER
n(4) value(n) → stackA four-byte unsigned operand specifies the number of following bytes. These bytes define the value of a signed integer in two’s-complement form. The first byte of the value is the least significant byte.
FOP-SMALL-INTEGER
n(1) value(n) → stackA one-byte unsigned operand specifies the number of following bytes. These bytes define the value of a signed integer in two’s-complement form. The first byte of the value is the least significant byte.
FOP-WORD-INTEGER
value(4) → stackA four-byte signed integer (in the range -231 to 231-1) follows the operation code. A LISP integer (fixnum or bignum) with that value is constructed and pushed onto the stack.
FOP-BYTE-INTEGER
value(1) → stackA one-byte signed integer (in the range -128 to 127) follows the operation code. A LISP integer (fixnum or bignum) with that value is constructed and pushed onto the stack.
FOP-STRING
n(4) name(n) → stackThe four-byte operand n specifies the length of a string to construct. The characters of the string follow, one per byte. The constructed string is pushed onto the stack.
FOP-SMALL-STRING
n(1) name(n) → stackThe one-byte operand n specifies the length of a string to construct. The characters of the string follow, one per byte. The constructed string is pushed onto the stack.
FOP-VECTOR
n(4) → stackThe four-byte operand n specifies the length of a vector of LISP objects to construct. The elements of the vector are popped off the stack; the first one popped becomes the last element of the vector. The constructed vector is pushed onto the stack.
FOP-SMALL-VECTOR
n(1) → stackThe one-byte operand n specifies the length of a vector of LISP objects to construct. The elements of the vector are popped off the stack; the first one popped becomes the last element of the vector. The constructed vector is pushed onto the stack.
FOP-UNIFORM-VECTOR
n(4) → stackThe four-byte operand n specifies the length of a vector of LISP objects to construct. A single item is popped from the stack and used to initialize all elements of the vector. The constructed vector is pushed onto the stack.
FOP-SMALL-UNIFORM-VECTOR
n(1) → stackThe one-byte operand n specifies the length of a vector of LISP objects to construct. A single item is popped from the stack and used to initialize all elements of the vector. The constructed vector is pushed onto the stack.
FOP-INT-VECTOR
n(4) size(1) count(1) data(ceiling(n/count)ceiling(size*count/8)) → stack
The four-byte operand n specifies the length of a vector of unsigned integers to be constructed. Each integer is size bits big, and are packed in the data stream in sections of count apiece. Each section occupies an integral number of bytes. If the bytes of a section are lined up in a row, with the first byte read at the right, and successive bytes placed to the left, with the bits within a byte being arranged so that the low-order bit is to the right, then the integers of the section are successive groups of size bits, starting from the right and running across byte boundaries. (In other words, this is a consistent right-to-left convention.) Any bits wasted at the left end of a section are ignored, and any wasted groups in the last section are ignored. It is permitted for the loading implementation to use a vector format providing more precision than is required by size. For example, if size were 3, it would be permitted to use a vector of 4-bit integers, or even vector of general LISP objects filled with integer LISP objects. However, an implementation is expected to use the most restrictive format that will suffice, and is expected to reconstruct objects identical to those output if the Fasload file was produced by the same implementation. (For the PERQ U-vector formats, one would have size an element of {1, 2, 4, 8, 16}, and count=32/size; words could be read directly into the U-vector. This operation provides a very general format whereby almost any conceivable implementation can output in its preferred packed format, and another can read it meaningfully; by checking at the beginning for good cases, loading can still proceed quickly.) The constructed vector is pushed onto the stack.
FOP-UNIFORM-INT-VECTOR
n(4) size(1) value(ceiling(size/8)) → stackThe four-byte operand n specifies the length of a vector of unsigned integers to construct. Each integer is size bits big, and is initialized to the value of the operand value. The constructed vector is pushed onto the stack.
FOP-FLOAT
n(1) exponent(ceiling(n/8)) m(1) mantissa(ceiling(m/8)) → stackThe first operand n is one unsigned byte, and describes the number of
bits in the second operand exponent, which is a signed
integer in two’s-complement format. The high-order bits of
the last (most significant) byte of exponent shall equal the sign bit.
Similar remarks apply to m and mantissa. The value denoted by these
four operands is mantissax
2exponent-length(mantissa).
A floating-point number shall be constructed which has this value,
and then pushed onto the stack. That floating-point format should be used
which is the smallest (most compact) provided by the implementation which
nevertheless provides enough accuracy to represent both the exponent
and the mantissa correctly.
FOP-ALTER
index(1)Two items are popped from the stack; call the first newval and the second object. The component of object specified by index is altered to contain newval. The precise operation depends on the type of object:
A zero index means alter the car (perform RPLACA
),
and index=1 means alter the cdr (RPLACD
).
By definition these indices have the following meaning, and have nothing to do with the actual representation of symbols in a given implementation:
Alter value cell.
Alter function cell.
Alter property list (!).
Alter component number index of the vector.
Alter character number index of the string.
FOP-EVAL
→ stackPop an item from the stack and evaluate it (give it to EVAL
).
Push the result back onto the stack.
FOP-EVAL-FOR-EFFECT
Pop an item from the stack and evaluate it (give it to EVAL
).
The result is ignored.
FOP-FUNCALL
nargs(1) → stackPop nargs+1 items from the stack and apply the last one popped as a function to all the rest as arguments (the first one popped being the last argument). Push the result back onto the stack.
FOP-FUNCALL-FOR-EFFECT
nargs(1)Pop nargs+1 items from the stack and apply the last one popped as a function to all the rest as arguments (the first one popped being the last argument). The result is ignored.
FOP-CODE-FORMAT
id(1)The operand id is a unique identifier specifying the format
for following code objects. The operations FOP-CODE
and its relatives may not
occur in a group until after FOP-CODE-FORMAT
has appeared;
there is no default format. This is provided so that several
compiled code formats may co-exist in a file, and so that a loader
can determine whether or not code was compiled by the correct
compiler for the implementation being loaded into.
So far the following code format identifiers are defined:
PERQ
VAX
IBM RT PC
FOP-CODE
nitems(4) size(4) code(size) → stackA compiled function is constructed and pushed onto the stack.
This object is in the format specified by the most recent
occurrence of FOP-CODE-FORMAT
.
The operand nitems specifies a number of items to pop off
the stack to use in the "boxed storage" section. The operand code
is a string of bytes constituting the compiled executable code.
FOP-SMALL-CODE
nitems(1) size(2) code(size) → stackA compiled function is constructed and pushed onto the stack.
This object is in the format specified by the most recent
occurrence of FOP-CODE-FORMAT
.
The operand nitems specifies a number of items to pop off
the stack to use in the "boxed storage" section. The operand code
is a string of bytes constituting the compiled executable code.
FOP-STATIC-HEAP
Until further notice operations which allocate data structures may allocate them in the static area rather than the dynamic area. (The default area for allocation is the dynamic area; this default is reset whenever a new group is begun. This command is of an advisory nature; implementations with no static heap can ignore it.)
FOP-DYNAMIC-HEAP
Following storage allocation should be in the dynamic area.
FOP-VERIFY-TABLE-SIZE
size(4)If the current size of the table is not equal to size, then an inconsistency has been detected. This operation is inserted into a Fasload file purely for error-checking purposes. It is good practice for a compiler to output this at least at the end of every group, if not more often.
FOP-VERIFY-EMPTY-STACK
If the stack is not currently empty, then an inconsistency has been detected. This operation is inserted into a Fasload file purely for error-checking purposes. It is good practice for a compiler to output this at least at the end of every group, if not more often.
FOP-END-GROUP
This is the last operation of a group. If this is not the
last byte of the file, then a new group follows; the next
nine bytes must be "FASL FILE
".
FOP-POP-FOR-EFFECT
stack → One item is popped from the stack.
FOP-MISC-TRAP
→ stackA trap object is pushed onto the stack.
FOP-READ-ONLY-HEAP
Following storage allocation may be in a read-only heap. (For symbols, the symbol itself may not be in a read-only area, but its print name (a string) may be. This command is of an advisory nature; implementations with no read-only heap can ignore it, or use a static heap.)
FOP-CHARACTER
character(3) → stackThe three bytes specify the 24 bits of a CMU Common Lisp character object. The bytes, lowest first, represent the code, control, and font bits. A character is constructed and pushed onto the stack.
FOP-SHORT-CHARACTER
character(1) → stackThe one byte specifies the lower eight bits of a CMU Common Lisp character object (the code). A character is constructed with zero control and zero font attributes and pushed onto the stack.
FOP-RATIO
→ stackCreates a ratio from two integers popped from the stack. The denominator is popped first, the numerator second.
FOP-COMPLEX
→ stackCreates a complex number from two numbers popped from the stack. The imaginary part is popped first, the real part second.
FOP-LINK-ADDRESS-FIXUP
nargs(1) restp(1) offset(4) → stackValid only for when FOP-CODE-FORMAT corresponds to the Vax or the IBM RT PC. This operation pops a symbol and a code object from the stack and pushes a modified code object back onto the stack according to the needs of the runtime code linker on the Vax or IBM RT PC.
FOP-LINK-FUNCTION-FIXUP
offset(4) → stackValid only for when FOP-CODE-FORMAT corresponds to the Vax or the IBM RT PC. This operation pops a symbol and a code object from the stack and pushes a modified code object back onto the stack according to the needs of the runtime code linker on the Vax or the IBM RT PC.
FOP-FSET
Pops the top two things off of the stack and uses them as arguments to FSET (i.e. SETF of SYMBOL-FUNCTION).
FOP-LINK-ADDRESS-FIXUP
nargs flag offset Valid only when FOP-CODE-FORMAT corresponds to the IBM RT PC. This operation pops a symbol and a function object off the stack. The code vector in the function object is modified according to the needs of the runtime code linker of the IBM RT PC and pushed back on the stack. This FOP links in calls to other functions.
FOP-MISCOP-FIXUP
index(2) offset(4) Valid only when FOP-CODE-FORMAT corresponds to the IBM RT PC. This operation pops a code object from the stack and pushes a modified code object back onto the stack according to the needs of the runtime code linker on the IBM RT PC. This FOP links in calls to the assembler language support routines.
FOP-ASSEMBLER-ROUTINE
code-length Valid only when FOP-CODE-FORMAT corresponds to the IBM RT PC. This operation loads assembler code into the assembler code space of the currently running Lisp.
FOP-FIXUP-MISCOP-ROUTINE
Valid only when FOP-CODE-FORMAT corresponds to the IBM RT PC. This operation pops a list of external references, a list of external labels defined, the name, and the code address off the stack. This information is saved, so that after everything is loaded, all the external references can be resolved.
FOP-FIXUP-ASSEMBLER-ROUTINE
is similar to FOP-FIXUP-MISCOP-ROUTINE, except it is for internal assembler routines rather than ones visible to Lisp.
FOP-FIXUP-USER-MISCOP-ROUTINE
is similar to FOP-FIXUP-MISCOP-ROUTINE, except it is for routines written by users who have an extremely good understanding of the system internals.
FOP-USER-MISCOP-FIXUP
offset(4) is similar to FOP-MISCOP-FIXUP, but is used to link in user defined miscops.
FOP-END-HEADER
Indicates the end of a group header, as described above.