--- a
+++ b/doc/cmucl/internals/fasl.tex
@@ -0,0 +1,584 @@
+\chapter{Fasload File Format}% -*- Dictionary: design -*-
+\section{General}
+
+The purpose of Fasload files is to allow concise storage and rapid
+loading of Lisp data, particularly function definitions.  The intent
+is that loading a Fasload file has the same effect as loading the
+ASCII file from which the Fasload file was compiled, but accomplishes
+the tasks more efficiently.  One noticeable difference, of course, is
+that function definitions may be in compiled form rather than
+S-expression form.  Another is that Fasload files may specify in what
+parts of memory the Lisp data should be allocated.  For example,
+constant lists used by compiled code may be regarded as read-only.
+
+In some Lisp implementations, Fasload file formats are designed to
+allow sharing of code parts of the file, possibly by direct mapping
+of pages of the file into the address space of a process.  This
+technique produces great performance improvements in a paged
+time-sharing system.  Since the Mach project is to produce a
+distributed personal-computer network system rather than a
+time-sharing system, efficiencies of this type are explicitly {\it not}
+a goal for the CMU Common Lisp Fasload file format.
+
+On the other hand, CMU Common Lisp is intended to be portable, as it will
+eventually run on a variety of machines.  Therefore an explicit goal
+is that Fasload files shall be transportable among various
+implementations, to permit efficient distribution of programs in
+compiled form.  The representations of data objects in Fasload files
+shall be relatively independent of such considerations as word
+length, number of type bits, and so on.  If two implementations
+interpret the same macrocode (compiled code format), then Fasload
+files should be completely compatible.  If they do not, then files
+not containing compiled code (so-called "Fasdump" data files) should
+still be compatible.  While this may lead to a format which is not
+maximally efficient for a particular implementation, the sacrifice of
+a small amount of performance is deemed a worthwhile price to pay to
+achieve portability.
+
+The primary assumption about data format compatibility is that all
+implementations can support I/O on finite streams of eight-bit bytes.
+By "finite" we mean that a definite end-of-file point can be detected
+irrespective of the content of the data stream.  A Fasload file will
+be regarded as such a byte stream.
+
+\section{Strategy}
+
+A Fasload file may be regarded as a human-readable prefix followed by
+code in a funny little language.  When interpreted, this code will
+cause the construction of the encoded data structures.  The virtual
+machine which interprets this code has a {\it stack} and a {\it table},
+both initially empty.  The table may be thought of as an expandable
+register file; it is used to remember quantities which are needed
+more than once.  The elements of both the stack and the table are
+Lisp data objects.  Operators of the funny language may take as
+operands following bytes of the data stream, or items popped from the
+stack.  Results may be pushed back onto the stack or pushed onto the
+table.  The table is an indexable stack that is never popped; it is
+indexed relative to the base, not the top, so that an item once
+pushed always has the same index.
+
+More precisely, a Fasload file has the following macroscopic
+organization.  It is a sequence of zero or more groups concatenated
+together.  End-of-file must occur at the end of the last group.  Each
+group begins with a series of seven-bit ASCII characters terminated
+by one or more bytes of all ones \verb|#xFF|; this is called the
+{\it header}.  Following the bytes which terminate the header is the
+{\it body}, a stream of bytes in the funny binary language.  The body
+of necessity begins with a byte other than \verb|#xFF|.  The body is
+terminated by the operation {\tt FOP-END-GROUP}.
+
+The first nine characters of the header must be "{\tt FASL FILE}" in
+upper-case letters.  The rest may be any ASCII text, but by
+convention it is formatted in a certain way.  The header is divided
+into lines, which are grouped into paragraphs.  A paragraph begins
+with a line which does {\it not} begin with a space or tab character,
+and contains all lines up to, but not including, the next such line.
+The first word of a paragraph, defined to be all characters up to but
+not including the first space, tab, or end-of-line character, is the
+{\it name} of the paragraph.  A Fasload file header might look something like
+this:
+\begin{verbatim}
+FASL FILE >SteelesPerq>User>Guy>IoHacks>Pretty-Print.Slisp
+Package Pretty-Print
+Compiled 31-Mar-1988 09:01:32 by some random luser
+Compiler Version 1.6, Lisp Version 3.0.
+Functions: INITIALIZE DRIVER HACK HACK1 MUNGE MUNGE1 GAZORCH
+	   MINGLE MUDDLE PERTURB OVERDRIVE GOBBLE-KEYBOARD
+	   FRY-USER DROP-DEAD HELP CLEAR-MICROCODE
+	    %AOS-TRIANGLE %HARASS-READTABLE-MAYBE
+Macros:    PUSH POP FROB TWIDDLE
+\end{verbatim}
+{\it one or more bytes of \verb|#xFF|}
+
+The particular paragraph names and contents shown here are only intended as
+suggestions.
+
+\section{Fasload Language}
+
+Each operation in the binary Fasload language is an eight-bit
+(one-byte) opcode.  Each has a name beginning with "{\tt 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 "$\Rightarrow$ stack" means that the result is pushed onto the
+stack; "$\Rightarrow$ table" similarly means that the result is added to the
+table.  A construction like "{\it n}(1) {\it value}({\it n})" means that
+first a single byte {\it n} is read from the input stream, and this
+byte specifies how many bytes to read as the operand named {\it 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).
+
+\begin{description}
+\item[0:] \hspace{2em} {\tt 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.)
+
+\item[1:] \hspace{2em} {\tt FOP-POP} \hspace{2em} $\Rightarrow$ \hspace{2em} table \\
+One item is popped from the stack and added to the table.
+
+\item[2:] \hspace{2em} {\tt FOP-PUSH} \hspace{2em} {\it index}(4) \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
+Item number {\it index} of the table is pushed onto the stack.
+The first element of the table is item number zero.
+
+\item[3:] \hspace{2em} {\tt FOP-BYTE-PUSH} \hspace{2em} {\it index}(1) \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
+Item number {\it index} of the table is pushed onto the stack.
+The first element of the table is item number zero.
+
+\item[4:] \hspace{2em} {\tt FOP-EMPTY-LIST} \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
+The empty list ({\tt ()}) is pushed onto the stack.
+
+\item[5:] \hspace{2em} {\tt FOP-TRUTH} \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
+The standard truth value ({\tt T}) is pushed onto the stack.
+
+\item[6:] \hspace{2em} {\tt FOP-SYMBOL-SAVE} \hspace{2em} {\it n}(4) \hspace{2em} {\it name}({\it n})
+\hspace{2em} $\Rightarrow$ \hspace{2em} stack \& table\\
+The four-byte operand {\it 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.
+
+\item[7:] \hspace{2em} {\tt FOP-SMALL-SYMBOL-SAVE} \hspace{2em} {\it n}(1) \hspace{2em} {\it name}({\it n}) \hspace{2em} $\Rightarrow$ \hspace{2em} stack \& table\\
+The one-byte operand {\it 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.
+
+\item[8:] \hspace{2em} {\tt FOP-SYMBOL-IN-PACKAGE-SAVE} \hspace{2em} {\it index}(4)
+\hspace{2em} {\it n}(4) \hspace{2em} {\it name}({\it n})
+\hspace{2em} $\Rightarrow$ \hspace{2em} stack \& table\\
+The four-byte {\it index} specifies a package stored in the table.
+The four-byte operand {\it 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.
+
+\item[9:] \hspace{2em} {\tt FOP-SMALL-SYMBOL-IN-PACKAGE-SAVE}  \hspace{2em} {\it index}(4)
+\hspace{2em} {\it n}(1) \hspace{2em} {\it name}({\it n}) \hspace{2em}
+$\Rightarrow$ \hspace{2em} stack \& table\\
+The four-byte {\it index} specifies a package stored in the table.
+The one-byte operand {\it 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.
+
+\item[10:] \hspace{2em} {\tt FOP-SYMBOL-IN-BYTE-PACKAGE-SAVE} \hspace{2em} {\it index}(1)
+\hspace{2em} {\it n}(4) \hspace{2em} {\it name}({\it n})
+\hspace{2em} $\Rightarrow$ \hspace{2em} stack \& table\\
+The one-byte {\it index} specifies a package stored in the table.
+The four-byte operand {\it 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.
+
+\item[11:]\hspace{2em} {\tt FOP-SMALL-SYMBOL-IN-BYTE-PACKAGE-SAVE} \hspace{2em} {\it index}(1)
+\hspace{2em} {\it n}(1) \hspace{2em} {\it name}({\it n}) \hspace{2em}
+$\Rightarrow$ \hspace{2em} stack \& table\\
+The one-byte {\it index} specifies a package stored in the table.
+The one-byte operand {\it 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.
+
+\item[12:] \hspace{2em} {\tt FOP-UNINTERNED-SYMBOL-SAVE} \hspace{2em} {\it n}(4) \hspace{2em} {\it name}({\it n})
+\hspace{2em} $\Rightarrow$ \hspace{2em} stack \& table\\
+Like {\tt FOP-SYMBOL-SAVE}, except that it creates an uninterned symbol.
+
+\item[13:] \hspace{2em} {\tt FOP-UNINTERNED-SMALL-SYMBOL-SAVE} \hspace{2em} {\it n}(1)
+\hspace{2em} {\it name}({\it n}) \hspace{2em} $\Rightarrow$ \hspace{2em} stack
+\& table\\
+Like {\tt FOP-SMALL-SYMBOL-SAVE}, except that it creates an uninterned symbol.
+
+\item[14:] \hspace{2em} {\tt FOP-PACKAGE} \hspace{2em} $\Rightarrow$ \hspace{2em} table \\
+An item is popped from the stack; it must be a symbol.	The package of
+that name is located and pushed onto the table.
+
+\item[15:] \hspace{2em} {\tt FOP-LIST} \hspace{2em} {\it length}(1) \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
+The unsigned operand {\it 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"
+{\it length} times.
+(Lists of length greater than 255 can be made by using {\tt FOP-LIST*}
+repeatedly.)
+
+\item[16:] \hspace{2em} {\tt FOP-LIST*} \hspace{2em} {\it length}(1) \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
+This is like {\tt FOP-LIST} except that the constructed list is terminated
+not by {\tt ()} (the empty list), but by an item popped from the stack
+before any others are.	Therefore {\it 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"
+{\it length}+1 times.
+
+\item[17-24:] \hspace{2em} {\tt FOP-LIST-1}, {\tt FOP-LIST-2}, ..., {\tt FOP-LIST-8} \\
+{\tt FOP-LIST-{\it k}} is like {\tt FOP-LIST} with a byte containing {\it k}
+following it.  These exist purely to reduce the size of Fasload files.
+Measurements need to be made to determine the useful values of {\it k}.
+
+\item[25-32:] \hspace{2em} {\tt FOP-LIST*-1}, {\tt FOP-LIST*-2}, ..., {\tt FOP-LIST*-8} \\
+{\tt FOP-LIST*-{\it k}} is like {\tt FOP-LIST*} with a byte containing {\it k}
+following it.  These exist purely to reduce the size of Fasload files.
+Measurements need to be made to determine the useful values of {\it k}.
+
+\item[33:] \hspace{2em} {\tt FOP-INTEGER} \hspace{2em} {\it n}(4) \hspace{2em} {\it value}({\it n}) \hspace{2em}
+$\Rightarrow$ \hspace{2em} stack \\
+A 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.
+
+\item[34:] \hspace{2em} {\tt FOP-SMALL-INTEGER} \hspace{2em} {\it n}(1) \hspace{2em} {\it value}({\it n})
+\hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
+A 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.
+
+\item[35:] \hspace{2em} {\tt FOP-WORD-INTEGER} \hspace{2em} {\it value}(4) \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
+A four-byte signed integer (in the range $-2^{31}$ to $2^{31}-1$) follows the
+operation code.  A LISP integer (fixnum or bignum) with that value
+is constructed and pushed onto the stack.
+
+\item[36:] \hspace{2em} {\tt FOP-BYTE-INTEGER} \hspace{2em} {\it value}(1) \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
+A 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.
+
+\item[37:] \hspace{2em} {\tt FOP-STRING} \hspace{2em} {\it n}(4) \hspace{2em} {\it name}({\it n})
+\hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
+The four-byte operand {\it 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.
+
+\item[38:] \hspace{2em} {\tt FOP-SMALL-STRING} \hspace{2em} {\it n}(1) \hspace{2em} {\it name}({\it n}) \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
+The one-byte operand {\it 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.
+
+\item[39:] \hspace{2em} {\tt FOP-VECTOR} \hspace{2em} {\it n}(4) \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
+The four-byte operand {\it 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.
+
+\item[40:] \hspace{2em} {\tt FOP-SMALL-VECTOR} \hspace{2em} {\it n}(1) \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
+The one-byte operand {\it 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.
+
+\item[41:] \hspace{2em} {\tt FOP-UNIFORM-VECTOR} \hspace{2em} {\it n}(4) \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
+The four-byte operand {\it 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.
+
+\item[42:] \hspace{2em} {\tt FOP-SMALL-UNIFORM-VECTOR} \hspace{2em} {\it n}(1) \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
+The one-byte operand {\it 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.
+
+\item[43:] \hspace{2em} {\tt FOP-INT-VECTOR} \hspace{2em} {\it len}(4) \hspace{2em}
+{\it size}(1) \hspace{2em} {\it data}($\left\lceil len*count/8\right\rceil$)
+\hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
+The four-byte operand {\it n} specifies the length of a vector of
+unsigned integers to be constructed.   Each integer is {\it size}
+bits long, and is packed according to the machine's native byte ordering.
+{\it size} must be a directly supported i-vector element size.  Currently
+supported values are 1,2,4,8,16 and 32.
+
+\item[44:] \hspace{2em} {\tt FOP-UNIFORM-INT-VECTOR} \hspace{2em} {\it n}(4) \hspace{2em} {\it size}(1) \hspace{2em}
+{\it value}(@ceiling<{\it size}/8>) \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
+The four-byte operand {\it n} specifies the length of a vector of unsigned
+integers to construct.
+Each integer is {\it size} bits big, and is initialized to the value
+of the operand {\it value}.
+The constructed vector is pushed onto the stack.
+
+\item[45:] Unused
+
+\item[46:] \hspace{2em} {\tt FOP-SINGLE-FLOAT} \hspace{2em} {\it data}(4) \hspace{2em}
+$\Rightarrow$ \hspace{2em} stack \\
+The {\it data} bytes are read as an integer, then turned into an IEEE single
+float (as though by {\tt make-single-float}).
+
+\item[47:] \hspace{2em} {\tt FOP-DOUBLE-FLOAT} \hspace{2em} {\it data}(8) \hspace{2em}
+$\Rightarrow$ \hspace{2em} stack \\
+The {\it data} bytes are read as an integer, then turned into an IEEE double
+float (as though by {\tt make-double-float}).
+
+\item[48:] \hspace{2em} {\tt FOP-STRUCT} \hspace{2em} {\it n}(4) \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
+The four-byte operand {\it n} specifies the length structure to construct.  The
+elements of the vector are popped off the stack; the first one popped becomes
+the last element of the structure.  The constructed vector is pushed onto the
+stack.
+
+\item[49:] \hspace{2em} {\tt FOP-SMALL-STRUCT} \hspace{2em} {\it n}(1) \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
+The one-byte operand {\it n} specifies the length structure to construct.  The
+elements of the vector are popped off the stack; the first one popped becomes
+the last element of the structure.  The constructed vector is pushed onto the
+stack.
+
+\item[50-52:] Unused
+
+\item[53:] \hspace{2em} {\tt FOP-EVAL} \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
+Pop an item from the stack and evaluate it (give it to {\tt EVAL}).
+Push the result back onto the stack.
+
+\item[54:] \hspace{2em} {\tt FOP-EVAL-FOR-EFFECT} \\
+Pop an item from the stack and evaluate it (give it to {\tt EVAL}).
+The result is ignored.
+
+\item[55:] \hspace{2em} {\tt FOP-FUNCALL} \hspace{2em} {\it nargs}(1) \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
+Pop {\it 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.
+
+\item[56:] \hspace{2em} {\tt FOP-FUNCALL-FOR-EFFECT} \hspace{2em} {\it nargs}(1) \\
+Pop {\it 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.
+
+\item[57:] \hspace{2em} {\tt FOP-CODE-FORMAT} \hspace{2em} {\it implementation}(1)
+\hspace{2em} {\it version}(1) \\
+This FOP specifiers the code format for following code objects.  The operations
+{\tt FOP-CODE} and its relatives may not occur in a group until after {\tt
+FOP-CODE-FORMAT} has appeared; there is no default format.  The {\it
+implementation} is an integer indicating the target hardware and environment.
+See {\tt compiler/generic/vm-macs.lisp} for the currently defined
+implementations.  {\it version} for an implementation is increased whenever
+there is a change that renders old fasl files unusable.
+
+\item[58:] \hspace{2em} {\tt FOP-CODE} \hspace{2em} {\it nitems}(4) \hspace{2em} {\it size}(4) \hspace{2em}
+{\it code}({\it size}) \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
+A compiled function is constructed and pushed onto the stack.
+This object is in the format specified by the most recent
+occurrence of {\tt FOP-CODE-FORMAT}.
+The operand {\it nitems} specifies a number of items to pop off
+the stack to use in the "boxed storage" section.  The operand {\it code}
+is a string of bytes constituting the compiled executable code.
+
+\item[59:] \hspace{2em} {\tt FOP-SMALL-CODE} \hspace{2em} {\it nitems}(1) \hspace{2em} {\it size}(2) \hspace{2em}
+{\it code}({\it size}) \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
+A compiled function is constructed and pushed onto the stack.
+This object is in the format specified by the most recent
+occurrence of {\tt FOP-CODE-FORMAT}.
+The operand {\it nitems} specifies a number of items to pop off
+the stack to use in the "boxed storage" section.  The operand {\it code}
+is a string of bytes constituting the compiled executable code.
+
+\item[60-61:] Unused
+
+\item[62:] \hspace{2em} {\tt FOP-VERIFY-TABLE-SIZE} \hspace{2em} {\it size}(4) \\
+If the current size of the table is not equal to {\it 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.
+
+\item[63:] \hspace{2em} {\tt 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.
+
+\item[64:] \hspace{2em} {\tt 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 "{\tt FASL FILE}".
+
+\item[65:] \hspace{2em} {\tt FOP-POP-FOR-EFFECT} \hspace{2em} stack \hspace{2em} $\Rightarrow$ \hspace{2em} \\
+One item is popped from the stack.
+
+\item[66:] \hspace{2em} {\tt FOP-MISC-TRAP} \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
+A trap object is pushed onto the stack.
+
+\item[67:] Unused
+
+\item[68:] \hspace{2em} {\tt FOP-CHARACTER} \hspace{2em} {\it character}(3) \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
+The three bytes are read as an integer then converted to a character.  This FOP
+is currently rather useless, as extended characters are not supported.
+
+\item[69:] \hspace{2em} {\tt FOP-SHORT-CHARACTER} \hspace{2em} {\it character}(1) \hspace{2em}
+$\Rightarrow$ \hspace{2em} stack \\
+The one byte specifies the code of a Common Lisp character object.  A character
+is constructed and pushed onto the stack.
+
+\item[70:] \hspace{2em} {\tt FOP-RATIO} \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
+Creates a ratio from two integers popped from the stack.
+The denominator is popped first, the numerator second.
+
+\item[71:] \hspace{2em} {\tt FOP-COMPLEX} \hspace{2em} $\Rightarrow$ \hspace{2em} stack \\
+Creates a complex number from two numbers popped from the stack.
+The imaginary part is popped first, the real part second.
+
+\item[72-73:] Unused
+
+\item[74:] \hspace{2em} {\tt FOP-FSET} \hspace{2em} \\
+Except in the cold loader (Genesis), this is a no-op with two stack arguments.
+In the initial core this is used to make DEFUN functions defined at cold-load
+time so that global functions can be called before top-level forms are run
+(which normally installs definitions.)  Genesis pops the top two things off of
+the stack and effectively does (SETF SYMBOL-FUNCTION).
+
+\item[75:] \hspace{2em} {\tt FOP-LISP-SYMBOL-SAVE} \hspace{2em} {\it n}(4) \hspace{2em} {\it name}({\it n})
+\hspace{2em} $\Rightarrow$ \hspace{2em} stack \& table\\
+Like {\tt FOP-SYMBOL-SAVE}, except that it creates a symbol in the LISP
+package.
+
+\item[76:] \hspace{2em} {\tt FOP-LISP-SMALL-SYMBOL-SAVE} \hspace{2em} {\it n}(1)
+\hspace{2em} {\it name}({\it n}) \hspace{2em} $\Rightarrow$ \hspace{2em} stack
+\& table\\
+Like {\tt FOP-SMALL-SYMBOL-SAVE}, except that it creates a symbol in the LISP
+package.
+
+\item[77:] \hspace{2em} {\tt FOP-KEYWORD-SYMBOL-SAVE} \hspace{2em} {\it n}(4) \hspace{2em} {\it name}({\it n})
+\hspace{2em} $\Rightarrow$ \hspace{2em} stack \& table\\
+Like {\tt FOP-SYMBOL-SAVE}, except that it creates a symbol in the
+KEYWORD package.
+
+\item[78:] \hspace{2em} {\tt FOP-KEYWORD-SMALL-SYMBOL-SAVE} \hspace{2em} {\it n}(1)
+\hspace{2em} {\it name}({\it n}) \hspace{2em} $\Rightarrow$ \hspace{2em} stack
+\& table\\
+Like {\tt FOP-SMALL-SYMBOL-SAVE}, except that it creates a symbol in the
+KEYWORD package.
+
+\item[79-80:] Unused
+
+\item[81:] \hspace{2em} {\tt FOP-NORMAL-LOAD}\\
+This FOP is used in conjunction with the cold loader (Genesis) to read
+top-level package manipulation forms.  These forms are to be read as though by
+the normal loaded, so that they can be evaluated at cold load time, instead of
+being dumped into the initial core image.  A no-op in normal loading.
+
+\item[82:] \hspace{2em} {\tt FOP-MAYBE-COLD-LOAD}\\
+Undoes the effect of {\tt FOP-NORMAL-LOAD}. 
+
+\item[83:] \hspace{2em} {\tt FOP-ARRAY} \hspace{2em} {\it rank}(4)
+\hspace{2em} $\Rightarrow$ \hspace{2em} stack\\
+This operation creates a simple array header (used for simple-arrays with rank
+/= 1).  The data vector is popped off of the stack, and then {\it rank}
+dimensions are popped off of the stack (the highest dimensions is on top.)
+
+\item[84-139:] Unused
+
+\item[140:] \hspace{2em} {\tt FOP-ALTER-CODE} \hspace{2em} {\it index}(4)\\
+This operation modifies the constants part of a code object (necessary for
+creating certain circular function references.)  It pops the new value and code
+object are off of the stack, storing the new value at the specified index.
+
+\item[141:] \hspace{2em} {\tt FOP-BYTE-ALTER-CODE} \hspace{2em} {\it index}(1)\\
+Like {\tt FOP-ALTER-CODE}, but has only a one byte offset.
+
+\item[142:] \hspace{2em} {\tt FOP-FUNCTION-ENTRY} \hspace{2em} {\it index}(4)
+\hspace{2em} $\Rightarrow$ \hspace{2em} stack\\
+Initializes a function-entry header inside of a pre-existing code object, and
+returns the corresponding function descriptor.  {\it index} is the byte offset
+inside of the code object where the header should be plunked down.  The stack
+arguments to this operation are the code object, function name, function debug
+arglist and function type.
+
+\item[143:] Unused
+
+\item[144:] \hspace{2em} {\tt FOP-ASSEMBLER-CODE} \hspace{2em} {\it length}(4)
+\hspace{2em} $\Rightarrow$ \hspace{2em} stack\\
+This operation creates a code object holding assembly routines.  {\it length}
+bytes of code are read and placed in the code object, and the code object
+descriptor is pushed on the stack.  This FOP is only recognized by the cold
+loader (Genesis.)
+
+\item[145:] \hspace{2em} {\tt FOP-ASSEMBLER-ROUTINE} \hspace{2em} {\it offset}(4)
+\hspace{2em} $\Rightarrow$ \hspace{2em} stack\\
+This operation records an entry point into an assembler code object (for use
+with {\tt FOP-ASSEMBLER-FIXUP}).  The routine name (a symbol) is on stack top.
+The code object is underneath.  The entry point is defined at {\it offset}
+bytes inside the code area of the code object, and the code object is left on
+stack top (allowing multiple uses of this FOP to be chained.)  This FOP is only
+recognized by the cold loader (Genesis.)
+
+\item[146:] Unused
+
+\item[147:] \hspace{2em} {\tt FOP-FOREIGN-FIXUP} \hspace{2em} {\it len}(1)
+\hspace{2em} {\it name}({\it len})
+\hspace{2em} {\it offset}(4) \hspace{2em} $\Rightarrow$ \hspace{2em} stack\\
+This operation resolves a reference to a foreign (C) symbol.  {\it len} bytes
+are read and interpreted as the symbol {\it name}.  First the {\it kind} and the
+code-object to patch are popped from the stack.  The kind is a target-dependent
+symbol indicating the instruction format of the patch target (at {\it offset}
+bytes from the start of the code area.)  The code object is left on
+stack top (allowing multiple uses of this FOP to be chained.)
+
+\item[148:] \hspace{2em} {\tt FOP-ASSEMBLER-FIXUP} \hspace{2em} {\it offset}(4)
+\hspace{2em} $\Rightarrow$ \hspace{2em} stack\\
+This operation resolves a reference to an assembler routine.  The stack args
+are ({\it routine-name}, {\it kind} and {\it code-object}).  The kind is a
+target-dependent symbol indicating the instruction format of the patch target
+(at {\it offset} bytes from the start of the code area.)  The code object is
+left on stack top (allowing multiple uses of this FOP to be chained.)
+
+\item[149-199:] Unused
+
+\item[200:] \hspace{2em} {\tt FOP-RPLACA} \hspace{2em} {\it table-idx}(4)
+\hspace{2em} {\it cdr-offset}(4)\\
+
+\item[201:] \hspace{2em} {\tt FOP-RPLACD} \hspace{2em} {\it table-idx}(4)
+\hspace{2em} {\it cdr-offset}(4)\\
+These operations destructively modify a list entered in the table.  {\it
+table-idx} is the table entry holding the list, and {\it cdr-offset} designates
+the cons in the list to modify (like the argument to {\tt nthcdr}.)  The new
+value is popped off of the stack, and stored in the {\tt car} or {\tt cdr},
+respectively.
+
+\item[202:] \hspace{2em} {\tt FOP-SVSET} \hspace{2em} {\it table-idx}(4)
+\hspace{2em} {\it vector-idx}(4)\\
+Destructively modifies a {\tt simple-vector} entered in the table.  Pops the
+new value off of the stack, and stores it in the {\it vector-idx} element of
+the contents of the table entry {\it table-idx.}
+
+\item[203:] \hspace{2em} {\tt FOP-NTHCDR} \hspace{2em} {\it cdr-offset}(4)
+\hspace{2em} $\Rightarrow$ \hspace{2em} stack\\
+Does {\tt nthcdr} on the top-of stack, leaving the result there.
+
+\item[204:] \hspace{2em} {\tt FOP-STRUCTSET} \hspace{2em} {\it table-idx}(4)
+\hspace{2em} {\it vector-idx}(4)\\
+Like {\tt FOP-SVSET}, except it alters structure slots.
+
+\item[255:] \hspace{2em} {\tt FOP-END-HEADER} \\ Indicates the end of a group header,
+as described above.
+\end{description}