
                           BIF Documentation
                          By Joel Matthew Rees
                            19 January 1992


           BIF documentation Copyright Joel Matthew Rees 1992


In the spirit of fig-FORTH, the author grants permission to use and copy
this documentation freely, on condition that any distribution of
significant portions of the documentation is accompanied by the above
copyright notice and the following acknowledgement:

BIF is architecturally derived from fig-FORTH.  fig-FORTH comes courtesy
of the FORTH INTEREST GROUP, PO Box 1105, San Carlos, CA 94070.

The author also grants permission to use and copy the source and object
code for BIF freely, with the same stipulations, i. e.,
that any distribution of significant portions of either must be
accompanied by this notice, and the additional stipulation that any
distribution of the entire code, whether source, object, or both, must
be accompanied by the entire documentation, including Copyright and
acknowledgements.

This is not a commercial product; it was a student project, use it at
your own risk.  No warranty whatsoever is made concerning it.  (If, by
chance, anyone is interested in using BIF in a commercial product, I
would appreciate knowing about it in advance.) The author's intent is
only to make it available for experimentation, and it should be treated
as strictly experimental software.  DO NOT ATTEMPT TO ACCESS ORDINARY
DISKS FORMATTED FOR USE BY OTHER OPERATING SYSTEMS WHILE BIF IS RUNNING!

Contact as of January 2000:
					joel_rees@sannet.ne.jp
					http://www.page.sannet.ne.jp/joel_rees
					reiisi@nettaxi.com
					http://www.nettaxi.com/citizens/reiisi


*******************************************************************************
                          General Information


BIF (BInary tree, fig-FORTH) is a dialect of FORTH for the Tandy Color
Computer.  It is a direct-threaded version of the pre-FORTH-79 fORTH
interest group publication of FORTH (fig-FORTH), using a non-standard
binary tree dictionary structure.  The direct-threading mechanism uses
the direct-page addressing mode of the 6809, and thus may not be easily
adaptable to FORTH-83.  It also uses absolute addressing, and thus does
not comform to the requirements of OS-9.  (I am working on an
indirect-threaded version of BIF for OS-9 in my spare time.)

BIF.BIN is the executable object; after LOADMing it, EXEC the address
&H1300 (see below).  BIFSOURC.ARC contains the archived (TC31) source
files; the assembler used is Disk EDTASM+.  I used TSEdit to generate
the source files in EDTASM+ format:

line-number SPACE [label] TAB mnemonic etc. LF

Using a text editor to replace the macros with their expansions should
make it compatible with most other assemblers.  An object which will run
under the EDTASM+ "stand-alone" debugger may be generated by changing
ORG $1200 in BIF.ASM to ORG $3F00.

BIFSCREE.ARC contains the BIF/FORTH source for several utilities, the
assembler, and double integer definitions (TOOLS.G00) and a definition
pairing example (PAIRS.G28) useful for making paired lists.  Using
TOOLS.G00 and PAIRS.G28 directly will require moving the two files to
their original granules, 0 and 28, on an ECB disk.  Once they are moved,
protecting the BIF screens with ECB directory entries may be a good
idea.  But resist the temptation to use a text editor on them.  Messing
with the whitespace will move the source code out of alignment with the
physical FORTH/BIF screens, and thus cause the source code not to load.

If you want to look at these two files with an editor, I suggest copying
them to a different disk and looking at the copies.  Even my favorite
IBM PC editor, QEDIT, will insert a CR/LF at the end of every 512 bytes
on saving, which is not good.  (I wonder how many letters from OS-9
users it would take to convince the folks at SEMWARE/Applied Systems
Technologies to make an OS-9 version of their editor?)

For $5.00, to cover postage, time, and the cost of floppies, I will send
a copy of the BIF screens disk on a standard 5 1/4" (ECB formatted)
floppy.  If you request the EDTASM+ compatible source code, I will send
that as well, on the same format disks.  For $5.00 more, I will include
a photo-copy of the documentation (useful if you don't have a way to
print it).

The documentation which follows is written in the standard FORTH
documentation style.  It is not intended as a primer or study guide.
Brodie's Starting FORTH, Winfield's THE COMPLETE FORTH, or some other
text is suggested to those unfamiliar with FORTH.  Much of the code and
examples should work as shown in the textbooks I recommend Leo Brodie's
work, because he points out most of the places the user will have to
refer to this documentation.  Some of the descriptions are incomplete,
particularly where definitions are intended to be used inside other
definitions.

The object contains a simple one-sector editor (for 32-column screens)
in the EDITOR vocabulary.  It does not provide search and replace, but
it is sufficient, for the patient, to write code.  My apologies for it.
I did not have a Color Computer 3 when I wrote the original code, and
haven't had the time to update it.  Those with access to the fig-FORTH
Installation Manual should have no problem installing the editor shown
there.

The assembler in the BIF screens is a full postfix assembler.  The
double integer screens show a quick example of its use.


*******************************************************************************
                          Getting BIF Running


Before you start, remember that BIF has the same post-fix grammar as
FORTH.  Think Reverse Polish, as in HP calculators.

Computer:       Comments:

                In Disk ECB, type:
LOADM "BIF.BIN" from whichever drive it is on, then remove all disks and
EXEC &H1300     BIF should tell you it is running with
6809 BIF V1.0
OK
                At this point, see if BIF is really running by typing
VLIST           and hitting ENTER.  You should see a listing of your
                main vocabulary (symbol table) which should run on for
                about 200 entries, and then the computer responds with
OK              If this doesn't happen, you have a bad object file, get
                a new copy.  Otherwise, you have BIF!

                If you have my BIF screens disk, put it in drive 0.
                Then type
6 LOAD          to load the utilities starting at screen 6.  After the
                utilities are loaded, you can load the assembler by
                typing
DECIMAL 16 LOAD

                If you don't have the BIF screens disk with the error
                messages, type
0 WARNING !     and BIF responds with
OK              but now tells you error numbers instead of messages.

Okay, a few examples:

        42 EMIT

puts the ascii character 42 (asterisk if the current BASE is DECIMAL) on
the output device.

        5 6 * .

prints the product of 5 and 6 (30, base ten) on the output device.

        DECIMAL : CHARS 32 DO I . I EMIT CR LOOP ;
        HEX 45 CHARS

will set up a BIF "word" called CHARS, which, being invoked on the second
line, will print the characters and hexadecimal ascii codes from SPACE
up to, but not including, DASH.

The BIF screens disk should always be in drive 0 if you want real error
messages.  If you want to look at the message text, the messages are at
the front of TOOLS.G00, after the directory screen and title screen.
Each message takes exactly 32 characters, including spaces and
non-printing characters.  Numbering starts with 0. If you have some
other disk in drive 0 you will get funny and not exactly intelligent
error messages.  I know it's weird, but I was following the fig-FORTH
model, which is designed for very limited memory.

If you haven't been able to put the BIF screens disk together, you don't
really need it to play around with BIF, but do clear the WARNING
variable so BIF will know error messages are not available.  Aside from
the error messages in drive 0, there is nothing special about screens
disks, except they do not have directory tracks.  You should generally
not put them in your drives when running under BASIC (DECB), OS-9 or
some other system.  By tradition, programmers use the first several
screens as a hand-typed directory.  You can format fresh BIF disks with
either Disk Extended Color BASIC's DSKINI or OS-9's format.  BIF ignores
the directory information both systems write, so you also generally
should not put a real DECB or OS-9 disk in while BIF is running.

If you do format with OS-9, format single-sided (I used DECB's disk
interface routines so BIF can't do double sided) with as many tracks as
you want.  To use the extra tracks, or a third or fourth drive, you will
need to modify the DRIVE-OFFSET array.  Pick a standard disk
configuration and stick with it.

An important word of warning.  BIF, like FORTH, uses buffered I/O.  Your
screens are not actually saved to disk until you cause the system to
need enough new buffers to write your editing back to the disk.  To
force the system to save the buffers, give BIF the SAVE-BUFFERS command.


*******************************************************************************
                           BIF's QUICK Editor


EDITOR          gets you into the EDITOR vocabulary.
0 QLIST         lets you look at the first sector of the directory.
4 B/SCR * QLIST lets you look at the first eight error messages.
DECIMAL         makes sure your conversion base is base ten.
64 B/SCR * QUICK
                lets you edit the first sector of the pairing example.
                Use the cursor keys to move around; use the BREAK key to
                get out.  If you modified something you don't want to
                change, type
EMPTY-BUFFERS   and ENTER.  If you want to make sure your changes are
                written to the disk, type
SAVE-BUFFERS    and ENTER.

The QUICK editor is in the EDITOR vocabulary.  It is available at boot
up.  You'll need to get into the EDITOR vocabulary, to access it.  Pass
it a sector number, not a screen number.  Multiplying by B/SCR (which
happens to be 4) will convert a screen number to a sector number.  Add
1, 2, or 3 to the base sector number of a screen to get the sector
numbers for the second, third, and fourth sectors of that screen.

The editor has no find/replace or block functions.  Again I apologize
for the editor, but I found it surprisingly workable.  Note that the
utility screens contain routines to move/copy sectors, so all is not
entirely mud.  One more glitch.  Lower case letters will show as VDG
codes until you run the cursor over them.  What can I say?

During editing, all arrow keys are cursor controls.  Use SHIFT-LEFTARROW
for destructive backspace, SHIFT-DOWNARROW for `[' left bracket,
SHIFT-RIGHTARROW for `]' right bracket, SHIFT-UPARROW for `_' underscore
(back-arrow on CoCo2).  SHIFT-CLEAR escapes the UP-ARROW to provide the
`^' caret.  SHIFT-CLEAR also escapes itself to provide the backslash.

Perhaps this is as good a place as any to mention a few points of
terminology.  A block is a sector.  Sectors are numbered sequentially
from 0.  Sector numbering continues sequentially from drive n to drive
n+1, see DRIVE-OFFSET, but also see OFFSET.  A SCREEN is a kilobyte
worth of blocks, in this case, four 256-byte sectors.  SCREEN numbering
also begins with 0.  (SCREENs are called SCREENs because a SCREEN can be
displayed on 16 lines of a 64-column CRT screen.)  You will notice that
a CoCo 2 can't properly display and edit a whole SCREEN.  Finally,
forward blocks are control constructs, not disk sectors.


*******************************************************************************
                        The BIF Virtual Machine

{	bifc_vm.h	---
fig     6809
UP      [DP]    pointer to the per-USER variable table (USER Pointer)
IP      Y       pointer to the next definition (Instruction Pointer)
RP      S       return/control stack pointer
SP      U       parameter/data stack pointer
W       [S]     pointer to executing definition's parameter field
}
                        The BIF Virtual Machine

fig     6809
{	bifc_vm.c	bif.m	bifdp.a
NEXT    ( --- )         jmp [,y++] (macro in bif.m)
        Causes the next definition to execute.

DOCOL   ( *** IP )      jsr <XCOL (see bif.m, bifdp.a)
        Characteristic of a colon (:) definition.  Begins execution of a
        high-level definition, i. e., nests the definition and begins
        processing icodes.  Mechanically, it pushes the IP (Y register)
        and loads the Parameter Field Address of the definition which
        called it into the IP.
}
{	symbol.c	bif.m	bifdp.a
DOVAR   ( --- vadr )    jsr <XVAR (bif.m, bifdp.a)
        Characteristic of a VARIABLE.  A VARIABLE pushes its PFA address
        on the stack.  The parameter field of a VARIABLE is the actual
        allocation of the variable, so that pushing its address allows
        its contents to be @ed (fetched).  Ordinary arrays and strings
        that do not subscript themselves may be allocated by defining a
        variable and immediately ALLOTting the remaining space.
        VARIABLES are global to all users, and thus should have been
        hidden in resource monitors, but aren't.

DOCON   ( --- n )       jsr <XCON (bif.m, bifdp.a)
        Characteristic of a CONSTANT.  A CONSTANT simply loads its value
        from its parameter field and pushes it on the stack.

DOUSER  ( --- vadr )    jsr <XUSER (bif.m, bifdp.a)
        Characteristic of a per-USER variable. USER variables are
        similiar to VARIABLEs, but are allocated (by hand!) in the
        per-user table.  A USER variable's parameter field contains its
        offset in the per-user table.

DOVOC   ( --- )         jsr <XVOC (bif.m, bifdp.a)
        Characteristic of a VOCABULARY.  A VOCABULARY stores a pointer
        to itself in the current interpretation ROOT per-USER variable.
        It contains a pointer to the definition at the root of its
        symbol table tree.  This allows the symbol table routines to
        treat the root as a leaf node.  This is also not standard FORTH!

        ( --- PFA )     ( *** IP )      jsr <XDOES (routine in bifdp.a)
        Characteristic of a DOES> defined word.  The characteristics of
        DOES> definitions are written in high-level icodes rather than
        machine level code. The first parameter word points to the
        high-level characteristic.  This routine's job is to push the
        IP, load the high level characteristic pointer in IP, and leave
        the address following the characteristic pointer on the stack so
        the parameter field can be accessed.

The following are not standard FORTH characteristics:

DO1ARR  ( index --- eadr )      jsr <X1ARR (bif.m, bifdp.a)
        Characteristic of a linear array. Linear arrays take the top
        word on the stack as an index to the array, and return the
        address of the element indexed.  So this routine subtracts the
        base index of the array, limit checks the result, then
        multiplies by the size of the array elements.  If the index is
        out of bounds, it returns a NULL pointer (0).  At some point I
        intended to implement multi-dimensional arrays in a similar
        manner, but I haven't.  It would be a quick and interesting
        project for anyone interested.

DOUCON  ( --- n )       jsr <XUCON (bif.m, bifdp.a)
        Characteristic of a USER variable treated as a CONSTANT, i. e.,
        fetches the value stored at the specified offset in the per-user
        table.

        ( --- d )       jsr <XDCON (bifdp.a)
        Characteristic of a double integer constant; the parameter field
        contains two words instead of one, both of which get pushed.
}
{	unused
ADDTOP  (MACRO in BIF.M) is not a characteristic; is used in several
        routines to add a value to the top of stack.
}

One of the primary problems with extending BIF is that calls to the
built-in characteristics are not conform to ;CODE.  Defining definitions
which use (;CODE) to establish the characteristics of the
sybmbols/definitions they define will hav a three-byte code field, where
the built-in compiling definitions -- VARIABLE, (1ARRAY, etc.,)
CONSTANT, USER, :, and VOCABULARY have two-byte code fields.  One
specific example of the difficulties this can create is that
vocabularies with special properties built in BIF, rather than by hand,
can't be searched by BIF's symbol table search routine, -FIND.  Of
course, XVOC could be moved to VOCABULARY, where it belongs, (and might
also be changed to a DOES> definition, but I don't think that's
necessary on the 6809).


*******************************************************************************
                  The BIF Symbols/Definitions/Routines


I have added slightly to the FORTH documentation methods.  I also show
the results on the return stack and in the input buffer, where
appropriate.  The name on the left is the definition name, as it will be
found by ' (TICK) and the outer interpreter.  To the right I indicate
precedence (P for higher Precedence than definition) and restrictions (C
for Compile-only). Below the name, I indicate the assembler source
label, where it is different from the name.  The definitions on the
SCREENS disk also indicate screen and sector for the source.
  
The parameters attempt to be mnemonic.  It will help to remember that
there are no stack items smaller than 16 bits; character and byte
parameters will be integers with their high-bytes ignored.  Double
integers are 32 bits.  A further reminder, parameters are listed Pascal
order, first pushed first; thus, the right-most is at the top of stack,
or the lowest address.  I specify a list of doubles pushed onto the
stack (used in the assembler) as dl. Finally, I will try to mean 16-bit
integer when I say word, but I may sometimes slip and mean (per FORTH
jargon) a definition/routine.

Flags are slightly different than fig-FORTH -- true is set as -1, sensed
as non-zero.  False is zero, of course.

A number of routines (such as ENCLOSE) accept and return different
parameters than specified in fig-FORTH.  I assume that those for whom
this fact may be of consequence will have copies of the standard and can
compare at their leisure.

The definitions are not alphabetized, nor are they listed in order of
immediate interest, but they are organized by the source file they occur
in.  The following file descriptions are generally accurate, but some
code is out of place.

        BIF contains most of the virtual machine.

        BIF.M contains the inner interpreter macro, some important
        symbol table offsets, and a few other general EQUates and
        macros.

        BIFDP contains the rest of the virtual machine.

        BIFU contains the allocation of the per-user system variables.

        BIFST contains the boot up code and definitions.

        BIF1 contains most of the calculator-style expression evaluator.

        BIF2 is mostly constants and system variables, but contains the
        memory management primitives.

        Most of BIF3 is code which interacts with system variables, for
        example, the words which set the conversion base to sixteen,
        ten, or eight.

        BIF4 contains multiplication and division, and the disk
        interface primitives.

        BIF5 is mostly output formatting.

        BIF6 is mostly input formatting and terminal interface.

        BIF7 contains most of the dictionary (interactive symbol table)
        machinery.

Unless otherwise noted, all definitions are in the BIF vocabulary.

There is much that is not sacred about FORTH and its dialects.  For
many, the attraction of FORTH is the great abandon with which one may
play games with its inner workings.  I have taken a number of liberties
and these routines still function.  If you have an idea, back your disks
up and try it.


****          Definitions/Routines in BIF.ASM and BIFB.A:
{	vm_alu.c	bif.asm
@       ( adr --- n )
FETCH   Replace address on stack with the word at the address.


!       ( n adr --- )
STORE   Store second word on stack at address on top of stack.

LIT     ( --- n )                                               C
        Push the following word from the instruction stream as a
        literal, or immediate value.

DLIT    ( --- d )                                               C
        Push a double integer literal (see LIT).
}

{	bifc_vm.c	bif.asm
EXECUTE ( adr --- )                                             C
EXEC    Jump to address on stack.  Used by the "outer" interpreter to
        interactively invoke routines.  (Not compile-only in fig.)

0BRANCH ( f --- )                                               C
ZBR     BRANCH if flag is zero.

1BRANCH ( f --- )                                               C
TBR     BRANCH if not zero.  Not as useful as it might appear.

BRANCH  ( --- )                                                 C
        Add the following word from the instruction stream to the
        instruction pointer (Y++).  Causes a program branch.
}

(LOOP)  ( --- )         ( limit index *** limit index+1)        C
XLOOP                   ( limit index *** )
        Counting loop primitive.  The counter and limit are the top two
        words on the return stack.  If the updated index/counter does
        not exceed the limit, a branch occurs.  If it does, the branch
        does not occur, and the index and limit are dropped from the
        return stack.

(+LOOP) ( n --- )       ( limit index *** limit index+n )       C
XPLOOP                  ( limit index *** )
        Loop with a variable increment.  Terminates when the index
        crosses the boundary from one below the limit to the limit.  A
        positive n will cause termination if the result index equals the
        limit.  A negative n must cause the index to become less than
        the limit to cause loop termination.

(DO)    ( limit index --- )     ( *** limit index )
XDO     Move the loop parameters to the return stack.  Synonym for D>R.

I       ( --- index )           ( limit index *** limit index )
        Copy the loop index from the return stack.  Synonym for R.

J       ( --- index2 )  ( index2 limit1 index1 *** index2 limit1 index1 )
        Copy the outer loop index from the return stack.  As with (DO)
        and I, J may be useful outside looping contexts.

DIGIT   ( c base --- ff )
        ( c base --- n tf )
        Translate C in base, yielding a translation valid flag.  If the
        translation is not valid in the specified base, only the false
        flag is returned.

(FIND)  ( name vocptr --- locptr f )
PFIND   Search vocabulary for a symbol called name.  Name is a pointer
        to a NUL terminated string of characters without count, vocptr
        is a pointer to a pointer to a definition (the length byte of a
        symbol table entry).  Locptr is also a pointer to a pointer to a
        definition, such that, if the flag is false, a symbol with the
        name searched for may be inserted in proper order at that point.
        Vocptr and locptr may point to either the right or left entry of
        the order-parent entry in the symbol table, or to pointer to the
        root of a vocabulary.  HIDDEN (smudged) definitions are
        lexically less than their name strings.  Searches only the local
        vocabulary, from the order-parent node passed.  Uses (REFIND).

		vocptr is a pointer to the parameter field of a vocabulary 
		header.

ENCLOSE ( buffer c --- s length )
ENCLOS  Scan buffer for a symbol delimited by c or ASCII NUL; return the
        length of the symbol scanned and the address of its first
        character.  A length 0 and a pointer to a NUL means no symbol
        was scanned before NUL terminator was reached.  (Buffer is the
        address of the buffer array to scan.)

LITERAL ( n --- )                                               P
LITER   ( n --- n ) if interpreting.
        Compile n as a literal, if compiling.

DLITERAL        ( d --- )                                       P
DLITER          ( d --- d ) if interpreting.
        Compile d as a double literal, if compiling.

EMIT    ( c --- )
        Write c to the output device (screen or printer).  Uses the ECB
        device number at address $6F, -2 is printer, 0 is screen.

KEY     ( --- c )
        ( --- BREAK )
        Wait for a key from the keyboard.  If the key is BREAK, set the
        high byte (result $FF03).

?TERMINAL       ( --- f )
QTERM   Scan keyboard, but do not wait.  Return 0 if no key, BREAK
        ($ff03) if BREAK is pressed, or key currently pressed.

CR      ( --- )
        EMIT a Carriage Return (ASCII CR).

(;CODE) ( --- )         ( IP *** )                              C
XSCODE  Compile the latest symbol as a reference to a ;CODE definition;
        overwrite the first three (3!) bytes of the code field of the
        symbol found by LATEST with a jump to the low-level
        characteristic code provided in the defining definition, and pop
        IP.  The machine-level code which follows (;CODE) in the
        instruction stream is not executed by the defining symbol, but
        becomes the characteristic of the defined symbol.  This is the
        usual way to generate the characteristics of VARIABLEs,
        CONSTANTs, etc., when FORTH compiles itself.  BIF, however, was
        hand-optimized to take advantage of direct-page jumps.  So its
        pre-compiled defining symbols with low-level characteristics
        look different from those compiled by BIF, having two bytes in
        their code fields instead of three.

>PRT    ( --- )
TOPRT   Send output to printer via CoCo's ROM routines and the device
        number variable (see EMIT).

>VID    ( --- )
TOVID   Send output to CRT, converse of >PRT.

2*      ( n --- n*2 )
LSHIFT  Fast multiply by two.

2/      ( n --- n/2 )
RSHIFT  Fast divide by two.

(REFIND)        ( name vocptr --- name locptr f )
PREF    Search vocabulary for the first symbol called name.  (Will find
        HIDDEN/SMUDGEd definitions.)  Name is a pointer to a string of
        characters without count, vocptr is a pointer to a pointer to a
        definition (the length byte of a symbol table entry).  Locptr is
        also a pointer to a pointer to a definition, such that, if the
        pointer at the pointer is NULL, a symbol with the name searched
        for may be inserted in proper order at that point.  Vocptr and
        locptr may be either the right or left entry of the order-parent
        entry in the symbol table, or a pointer to the root of a
        vocabulary.  Flag f will indicate by offset whether the child or
        empty slot is a left link (LFTOFF), right link (RTOFF), or
        vocabulary (PFAOFF).

		vocptr is a pointer to the parameter field of a vocabulary 
		header.


****          Definitions/Routines in BIF1.A and BIF1B.A:

MOVE    ( source target count --- )
        Copy/move count words from source to target.  Moves ascending
        addresses, so that overlapping only works if the source is
        above the destination.

CMOVE   ( source target count --- )
        Copy/move count bytes from source to target.  Moves ascending
        addresses, so that overlapping only works if the source is
        above the destination.

U*      ( u1 u2 --- ud )
USTAR   Multiplies the top two unsigned integers, yielding a double
        integer product.

U/      ( ud u --- uremainder uquotient )
USLASH  Divides the top unsigned integer into the second and third words
        on the stack as a single unsigned double integer, leaving the
        remainder and quotient (quotient on top) as unsigned integers.
		
		The smaller the divisor, the more likely dropping the high word 
		of the quotient loses significant bits.

AND     ( n1 n2 --- n )
        Bitwise and the top two integers.

OR      ( n1 n2 --- n )
        Bitwise or.

XOR     ( n1 n2 --- n )
        Bitwise exclusive or.

SP@     ( --- adr )
SPFEH   Fetch the parameter stack pointer (before it is pushed).

SP!     ( whatever --- nothing )
SPSTO   Initialize the parameter stack pointer from the USER variable
        S0.  Effectively clears the stack.

RP!     ( whatever *** nothing )
RPSTO   Initialize the return stack pointer from the USER variable R0.
        Effectively aborts all in process definitions, except the active
        one.  An emergency measure, to be sure.

;S      ( ip *** )
SEMIS   Pop IP from return stack (return from high-level definition).
        Can be used in a screen to force interpretion to terminate.

LEAVE   ( limit index *** index index )
        Force the terminating condition for the innermost loop by
        copying its index to its limit.  Termination is postponed until
        the next LOOP or +LOOP instruction is executed.  The index
        remains available for use until the LOOP or +LOOP instruction is
        encountered.

>R      ( n --- )               ( *** n )                       C
TOR     Move top of parameter stack to top of return stack.

R>      ( --- n )               (n *** )                        C
RFROM   Move top of return stack to top of parameter stack.

R       ( --- n )               ( n *** n )
        Copy the top of return stack to top of parameter stack.  A
        synonym for I.

=       ( n1 n2 --- n1=n2 )
EQ      Flag true if n1 and n2 are equal, otherwise false.

<       ( n1 n2 --- n1<n2 )
LT      Flag true if n1 is less than n2, otherwise false.

0=      ( n --- n=0 )
ZEQ     Logically invert top of stack; or flag true if top is zero,
        otherwise false.

0<      ( n --- n<0 )
ZLESS   Flag true if top is negative (MSbit set), otherwise false.

>       ( n1 n2 --- n1>n2 )
GT      Flag true if n1 is greater than n2, false otherwise.

{	vm_alu.c	bif1.a
+       ( n1 n2 --- n1+n2 )
ADD     Add top two words.

-       ( n1 n2 --- n1-n2 )
SUB     Subtract top two words.
}

D+      ( d1 d2 --- d1+d2 )
DADD    Add top two double integers.

D-      ( d1 d2 --- d1-d2 )
DSUB    Subtract top two double integers.

MINUS   ( n --- -n )
        Negate (two's complement) top of stack.

DMINUS  ( d --- -d )
        Negate (two's complement) top two words on stack as a double
        integer.

OVER    ( n1 n2 --- n1 n2 n1 )
        Push a copy of the second word on stack.

DROP    ( n --- )
        Discard the top word on stack.

SWAP    ( n1 n2 --- n2 n1 )
        Swap the top two words on stack.

DUP     ( n1 --- n1 n1 )
        Push a copy of the top word on stack.

+!      ( n adr --- )
ADDSTO  Add the second word on stack to the word at the adr on top of
        stack.

TOGGLE  ( adr b --- )
TOG     Exclusive or byte at adr with low byte of top word.

C@      ( adr --- b )
CFEH    Replace address on top of stack with the byte at the address.
        High byte of result is clear.

C!      ( b adr --- )
CSTO    Store low byte of second word on stack at address on top of
        stack.  High byte is ignored.

ROT     ( n1 n2 n3 --- n2 n3 n1 )
        Rotate the top three words on stack, bringing the third word to
        the top.

BACK    ( adr --- )                                             C
        Calculate a back reference from HERE and compile it.  The result
        compiled is adr-HERE-2, being adjusted for post-increment
        addressing.

NOT     ( n --- ~n )
        Bit (one's) complement the top of stack.

'       ( --- ) compiling                                       P
TICK    ( --- adr ) interpreting
        { ' name } input
        Parse a symbol name from input and search, -DFIND, the
        dictionary for it; compile the address as a literal if
        compiling, otherwise just push it.  Recursively searches parent
        vocabularies, aborts if the parsed symbol name is not found.

-->     ( --- )                                                 P
NEXSCR  Continue interpreting source code on the next screen.

1ARRAY  ( start end size --- )
ONEARR  { 1ARRAY name } input
        Parse name and compile it as a linear array of size elements
        from start index to end index inclusive.  The number of bytes in
        the array is (end-start+1)*size.  The 1ARRAY characteristic is a
        direct page routine.

UTILITIES       ( --- )
UTIL    The UTILITIES vocabulary.

DP@     ( --- adr )                             in UTILITIES
DPFEH   Calculate and push the address of the direct page.

DCONSTANT       ( d --- )
DCON    { DCONSTANT name } input
        Parse name and compile it as a double constant with a value of
        d.  The DCONSTANT characteristic is a direct page routine.

SWAB    ( n --- ns )
        Swap the bytes of the top word on stack.

SWAN    ( n --- ns )
        Swap the nibbles of the top word on stack.  The low-level code
        looks funny, but it was the fastest way I could think up.


****          Definitions/Routines in BIF2.A and BIF2B.A:

Increments and decrements for top of stack:
1+      ADD1    ( n --- n+1 )
1-      SUB1    ( n --- n-1 )
2+      ADD2    ( n --- n+2 )
2-      SUB2    ( n --- n-2 )

Constants:
0       ZERO    ( --- 0 )
1       ONE     ( --- 1 )
-1      MONE    ( --- -1 )
2       TWO     ( --- 2 )
3       THREE   ( --- 3 )
BL      BL      ( --- SP )      ASCII SPACE character
C/L     CPERL   ( --- 32 )      The number of columns per line on the
                CRT.  Determines the length of error messages and the
                width and length of screen listings, among other things.
FIRST           ( --- adr )     The base of the disk buffer space.
LIMIT           ( --- adr )     The limit of the disk buffer space.
B/BUF   BPBUF   ( --- 256 )     The size, in bytes, of a buffer.
B/SCR   BPSCR   ( --- 4 )       The size, in buffers, of a screen.

+ORIGIN ( n --- adr )
PORIG   Calculate the address of the (n/2)th entry in the boot-up
        parameter table.  (Adds the base of the boot-up table to n.)

Variables:
TIB             ( --- vadr )    Terminal Input Buffer address.  Note
                that is a variable, so users may allocate their own
                buffers, but it must be @ed.
WARNING WARN    ( --- vadr )    Availability of error messages on disk.
                Contains 1 if messages available, 0 if not, -1 if a disk
                error has occurred.
				In bif-c, add 2 for internal error strings.
FENCE           ( --- vadr )    Boundary for FORGET.
DP      DPC     ( --- vadr )    Dictionary pointer, fetched by HERE.
ROOT            ( --- vadr )    Current local/context interpretation
                vocabulary root.  Not a fig variable.
BLK             ( --- vadr )    Block being interpreted.  Zero refers to
                terminal.
IN              ( --- vadr )    Input buffer offset/cursor.
OUT             ( --- vadr )    Output buffer offset/cursor.
SCR             ( --- vadr )    Screen being edited.  Unused in BIF.
OFFSET          ( --- vadr )    Sector offset for LOADing screens, set
                by DRIVE to make a new drive the default.
STATE           ( --- vadr )    Compiler/interpreter state.
BASE            ( --- vadr )    Numeric conversion base.
DPL             ( --- vadr )    Output decimal point locator.
FLD             ( --- vadr )    Field width for I/O formatting.
CSP             ( --- vadr )    Compiler stack mark for stack check.
R#      RNUM    ( --- vadr )    Editing cursor location.  Unused in BIF.
HLD             ( --- vadr )    Pointer to last HELD character in PAD.
FOREWARD FORE   ( --- vadr )    Pointer to earliest definition in active
                forward block. Not fig.
CURRENT CURR    ( --- vadr )    NFA of LATEST definition.  Not fig.
PREV            ( --- vadr )    Most Recently Used buffer.
USE             ( --- vadr )    Least Recently Used buffer.
DROOT           ( --- vadr )    Current defining/compiling vocabulary
                root.  Not fig.

HERE    ( --- adr )
        Get contents of DP, with heap/stack overflow ERROR check.  More
        than a pseudo-constant.

ALLOT   ( n --- )
        Increase heap (add n to DP), ERROR check stack/heap.

,       ( n --- )
COMMA   Store word n at DP++, ERROR check stack/heap.

C,      ( b --- )
CCOMMA  Store byte b at DP+, ERROR check stack/heap.

SPACE   ( --- )
        EMIT a SPACE.

-DUP    ( 0 --- 0 )
DDUP    ( n --- n n )
        DUP if non-zero.

?CST    ( --- f )
QCST    Push compile/interpret state bits.

IF      ( --- cdptr $4946 )                                     P,C
        Compile a 0BRANCH and dummy offset and push IF reference to fill
        in and IF control construct flag.

ELSE    ( cdptr1 $4946 --- cdptr2 $4946 )                       P,C
        ERROR check IF flag, compile BRANCH with dummy offset, resolve
        IF reference (FILL-IN offset-2 to HERE at cdptr1), and leave
        reference to BRANCH for ELSE.


ENDIF   ( cdptr $4946 --- )                                     P,C
        ERROR check IF flag, resolve IF reference (FILL-IN offset-2 to
        HERE at cdptr) and pop reference/flag.


****          Definitions/Routines in BIF3.A and BIF3B.A:

LATEST  ( --- symptr )
        Fetch CURRENT as a per-USER constant.

Symbol table conversions:
LFA     ( n --- n+LFAOFF )      Convert NFA (not PFA) to LFA.
	--> Convert header address to LFA.
CFA     ( n --- n+CFAOFF )      Convert NFA (not PFA) to CFA.
	--> Convert header address to CFA.
GFA     ( n --- n+GFAOFF )      Convert NFA (not PFA) to CFA.
	--> Convert header address to GFA.
PFA     ( n --- n+PFAOFF )      Convert NFA to PFA.
	--> Convert header address to PFA.
NFA     ( n --- n-PFAOFF )      Convert PFA to NFA.
	--> Convert PFA to header address.
        NFA is the address of the length byte in a symbol table header.
	--> Now we use the header address instead of the NFA.
        PFA is the address at which a high-level definition's icode list
        begins, or a variable's, constant's, or vocabulary's value is
        stored.
        CFA is where a definition's code begins, or where the jump to
        its characteristic is stored.
        LFA is the address of a definition's allocation link.
        GFA is the address of a definition's vocabulary link.

!CSP    ( --- )
STOCSP  Save the parameter stack pointer in CSP for compiler checks.

Set the conversion base:
HEX             ( --- )         Sixteen.
DECIMAL DEC     ( --- )         Ten.
OCTAL   OCT     ( --- )         Eight.

FILL    ( adr n b --- )
        Fill n bytes at adr with b.

ERASE   ( adr n --- )
        Fill n bytes with 0.

BLANKS  ( adr n --- )
        Fill n bytes with ASCII SPACE.

HOLD    ( c --- )
        Format a character at the left of the HLD output buffer.

PAD     ( --- adr )
        Give the address of the output PAD buffer.  Not same as fig. PAD
        points to the end of a 34 byte buffer for numeric conversion.

S->D    ( n0 --- d0 )
STOD    Sign extend n0 to a double integer.

+-      ( n0 n1>=0 --- n0 )
CHS     ( n0 n1<0 --- -n0 )
        Change sign of second iff top is negative.

D+-     ( d0 n0>=0 --- d0 )
DCHS    ( d0 n0<0 --- -d0 )
        Change sign of second and third as double iff top is negative.

ABS     ( n>=0 --- n )
        ( n<0 --- -n )
        Change the top of stack to its absolute value.

DABS    ( d>=0 --- d )
        ( d<0 --- -d )
        Change the top double to its absolute value.

MIN     ( n0 n1 --- min(n0,n1) )
        Leave the minimum of the top two integers.

MAX     ( n0 n1 --- max(n0,n1) )
        Leave the maximum of the top two integers.

[       ( --- )                                                 P
LBRAK   Clear the compile state bits (shift to interpret).

]       ( --- )
RBRAK   Set the compile state bits (shift to compile).

IMMEDIATE       ( --- )
IMMED   Toggle precedence bit of LATEST definition header.  During
        compiling, most symbols scanned are compiled.  IMMEDIATE
        definitions execute whenever the outer INTERPRETer scans them,
        but may be compiled via ' (TICK).

SMUDGE  ( --- )
        Toggle HIDDEN bit of LATEST definition header, to hide it until
        defined or reveal it after definition.

COMPILE-ONLY    ( --- )
COMPO   Toggle compile only bit of LATEST definition header.

COUNT   ( strptr --- strptr+1 count )
        Convert counted string to string and count.  (Fetch the byte at
        strptr, post-increment.)

-TRAILING       ( strptr count1 --- strptr count2 )
DTRAIL  Supress trailing blanks (subtract count of trailing blanks from
        strptr).

(MACHINE)       ( ip *** )                                      C
XMACH   Change from executing icodes to machine code in a definition by
        saving IP and jumping to it after popping the old IP.

TYPE    ( strptr count --- )
        EMIT count characters at strptr.

CTS-TYPE     ( adr --- )                             in UTILITIES (bif-c)
CTD_TYPE   TYPE the (byte) counted string at adr.

(.")    ( --- )                                                 C
XDOTQ   TYPE counted string out of instruction stream (updating IP).

ID.     ( symptr --- )
IDDOT   Print definition's name from its NFA.

FILL-IN ( cdptr --- )                                           C
FILLIN  Resolve the reference at cdptr by writing the offset from
        cdptr+2 to HERE at cdptr.  Offset is adjusted for post-increment
        IP (ldd ,y++).

BEGIN   ( --- cdptr $4245 )                                     P,C
        Push HERE for BACK reference for general (non-counting) loops,
        with BEGIN construct flag.

AGAIN   ( cdptr $4245 --- )                                     P,C
        ERROR check BEGIN flag, compile BRANCH and BACK resolve it to
        cdptr.

UNTIL   ( cdptr $4245 --- )                                     P,C
        ERROR check BEGIN flag, compile 0BRANCH and BACK resolve it to
        cdptr.

WHILE   ( $4245 --- $4245 cdptr $5748 )                         P,C
        ERROR check BEGIN flag, compile 0BRANCH with dummy offset, push
        WHILE reference -- HERE -- /flag on top of BEGIN reference/flag.

REPEAT  ( cdptr1 $4245 cdptr2 $5748 --- )                       P,C
        ERROR check WHILE and BEGIN flags, compile BRANCH and BACK fill
        cdptr1 reference, FILL-IN 0BRANCH reference at cdptr2.

DO      ( --- cdptr $444F )                                     P,C
        Compile (DO), push HERE for BACK refenece, and push DO control
        construct flag.


****          Definitions/Routines in BIF4.A and BIF4B.A:

M*      ( n1 n2 --- d )
MSTAR   Multiply top two words as signed integers with a signed double
        result.

M/      ( d n --- remainder quotient )
MSLASH  Divide signed double dividend d (2nd & 3rd words) by signed
        word divisor n (top) yielding signed word remainder and quotient.
        Quotient is top, remainder takes sign of dividend.
		
		Thus, dividend == quotient * divisor + remainder 
		with truncating toward zero.
		This can overflow in quotient.

*       ( multiplier multiplicand --- product )
STAR    Signed word multiply.

/MOD    ( dividend divisor --- remainder quotient )
SLAMOD  M/ in word-only form, i. e., signed division of 2nd word by top
        word yielding signed word quotient and remainder.

/       ( dividend divisor --- quotient )
SLASH   Signed word divide without remainder.

MOD     ( dividend divisor --- remainder )
        Remainder function, result takes sign of dividend.

*/MOD   ( multiplier multiplicand divisor --- remainder quotient )
SSMOD   Signed precise division of product: multiply 2nd and 3rd
        words on stack and divide the 31-bit product by the top word,
        leaving both quotient and remainder.  Remainder takes sign of
        product.  Guaranteed not to lose significant bits.

*/      ( multiplier multiplicand divisor --- quotient )
STARSL  */MOD without remainder.

M/MOD   ( ud1 u1 --- u2 ud2 )
MSMOD   U/ with an (unsigned) double quotient.  Guaranteed not to lose
        significant bits, if you are prepared to deal with them.

+BUF    ( buffer1 --- buffer2 f )
ADDBUF  Bump to next buffer, flag false if result is PREVious buffer,
        otherwise flag true.  Used in the LRU allocation routines.

UPDATE  ( --- )
        Mark PREVious buffer dirty, in need of being written out.

EMPTY-BUFFERS   ( --- )
EMTBUF  Mark all buffers empty.  Standard method of discarding changes.

DRIVE-OFFSET    ( n --- eadr )
DROFFS  1ARRAY of drive offsets (see DO1ARR in the description of the
        virtual machine).  Contains the size, in sectors, of four
        drives, plus a fifth entry to end the table if all four drives
        are defined.  To make drive 2 a 40 track SS-DD drive:
                40 18 * 2 DRIVE-OFFSET !
        (Formatting the extra tracks can be handled with OS-9.)

DRIVE   ( n --- )
        Add up the sector offset to sector 0 of drive n and store it in
        OFFSET.  This changes the logically lowest drive for LOADING.

R/W     ( buffer sector f --- )
RW      Read or Write the specified (absolute -- ignores OFFSET) sector
        from or to the specified buffer.  A zero flag specifies write,
        non-zero specifies read.  Sector is an unsigned integer, buffer
        is the buffer's address.  Uses the CoCo ROM disk routines.  This
        is where you would want to handle double-sided drives.

?ERROR  ( 0 n --- )             ( *** )
QERROR  ( true n --- IN BLK )   ( anything *** nothing )
        If flag is false, do nothing.  If flag is true, issue error
        MESSAGE and QUIT or ABORT, via ERROR.  Leaves cursor position
        (IN) and currently loading block number (BLK) on stack, for
        analysis.

?COMP   ( --- )                 ( *** )
QCOMP   ( --- IN BLK )          ( anything *** nothing )
        ERROR if not compiling.

?EXEC   ( --- )                 ( *** )
QEXEC   ( --- IN BLK )          ( anything *** nothing )
        ERROR if not executing.

?PAIRS  ( n1 n2 --- )           ( *** )
QPAIRS  ( n1 n2 --- IN BLK )    ( anything *** nothing )
        ERROR if n1 and n2 are unequal.  MESSAGE says compiled
        conditionals do not match.

?CSP    ( --- )                 ( *** )
QCSP    ( --- IN BLK )          ( anything *** nothing )
        ERROR if return/control stack is not at same level as last !CSP.
        Used to indicate that a definition has been left incomplete.
		*** Actually, this checks the parameter stack. ***

?LOADING        ( --- )         ( *** )
QLOAD   ( --- IN BLK )          ( anything *** nothing )
        ERROR if not loading, i. e., if BLK is non-zero. [correction: if BLK _is_ zero!]

COMPILE ( --- )
COMP    Compile an in-line literal value from the instruction stream.

LOOP    ( cdptr $444f --- )                                     P,C
        ERROR check DO flag, compile (LOOP), fill in BACK reference.

+LOOP   ( cdptr $444f --- )                                     P,C
PLOOP   ERROR check DO flag, compile (+LOOP), fill in BACK reference.

LOAD    ( n --- )
        Begin interpretation of screen (block) n.  See also NEXSRC,
        SEMIS, and ***NULLL****GGGGGHHHHTHNiTHNiTHNi

<BUILDS ( --- )                                                 C
BUILDS  Build a header for DOES> definitions.  Actually just compiles a
        CONSTANT zero which can be overwritten later by DOES>.  Note
        that <BUILDS is not IMMEDIATE, and therefore executes during a
        definition's run-time, rather than its compile-time.  It is not
        intended to be used directly, but rather so that one definition
        can build another.  Also, note that nothing particularly special
        happens in the defining definition until DOES> executes.  The
        name <BUILDS is intended to be a reminder of what is about to
        occur.

DOES>   ( --- )         ( IP *** )                              C
DOES    Define run-time behavior of definitions compiled/defined by a
        high-level defining definition -- the FORTH equivalent of a
        compiler-compiler.  DOES> assumes that the LATEST symbol table
        entry has at least one word of parameter field, which <BUILDS
        provides.  Note that DOES> is also not IMMEDIATE.  When the
        defining word containing DOES> executes the DOES> icode, it
        overwrites the LATEST symbol's CFA with jsr <XDOES, overwrites
        the first word of that symbol's parameter field with its own IP,
        and pops the previous IP from the return stack. The icodes which
        follow DOES> in the stream do not execute at the defining word's
        run-time. Examining XDOES in the virtual machine shows that the
        defined word will execute those icodes which follow DOES> at its
        own run-time.  The advantage of this kind of behaviour, which
        you will also note in ;CODE, is that the defined word can
        contain both operations and data to be operated on.  This is how
        FORTH data objects define their own behavior.  Finally, note
        that the effective code field for DOES> definitions is four
        bytes.

;CODE   ( --- )                                                 P,C
SCODE   ?CSP to see if there are loose ends in the defining definition
        before shifting to the assembler, compile (;CODE) in
        the defining definition's instruction stream, shift to
        interpreting, make the ASSEMBLER vocabulary current, and !CSP to
        mark the stack in preparation for assembling low-level code.
        Note that ;CODE, unlike DOES>, is IMMEDIATE, and compiles
        (;CODE),which will do the actual work of changing the LATEST
        definition's characteristic when the defining word runs.
        Assembly is done by the interpreter, rather than the compiler.
        I could have avoided the anomalous three-byte code fields by
        having ;CODE compile in the direct page jumps to the actual
        low-level characteristics in the defining definition, thus
        allowing (;CODE) to write a two-byte direct-page jumps into the
        code fields of defined words.  But that's a lot of work!


****          Definitions/Routines in BIF5.A and BIF5B.A:


IP,     ( --- )                                                 C
IPCOM   COMPILE a literal out of the instruction stream, without
        checking compiler state.  Used by the assembler to stuff
        op-codes into the instruction stream, since the assembler runs
        in interpretation mode.

?STACK  ( --- )                 ( *** )
QSTACK  ( --- IN BLK )          ( anything *** nothing )
        ERROR if either stack out of bounds, or on evidence of stack
        boundary problems.  There is a word below the bottom of each
        stack, which ABORT clears before it starts interpreting. In
        addition to checking that both stacks have not overflowed, this
        routine checks those two words, to see if underflow has
        occurred.

BUFFER  ( n --- buffer )
        Get a free buffer, assign it to block n, return buffer address.
        Will free a buffer by writing it, if necessary.  Does not
        actually read the block.  A bug in the fig LRU algorithm, which
        I have not fixed, gives the PREVious buffer if USE gets set to
        PREVious (the bug is that it happens).  This bug sometimes
        causes sector moves to become sector fills.

BLOCK   ( n --- buffer )
        Get BUFFER containing block n, relative to OFFSET.  If block n
        is not in a buffer, bring it in.  Returns buffer address.

(LINE)  ( line screen --- buffer C/L)
XLINE   Bring in the sector containing the specified line of the
        specified screen.  Returns the buffer address and the width of
        the screen.  Screen number is relative to OFFSET.  The line
        number may be beyond screen 4, (LINE) will get the appropriate
        screen.

.LINE   ( line screen --- )
DOTLIN  Print the line of the screen as found by (LINE), suppress
        trailing BLANKS.

SPACES  ( count --- )
        EMIT count spaces, for non-zero, non-negative counts.

<#      ( --- )
BEGHSH  Initialize HLD for converting a double integer.  Stores the PAD
        address in HLD.

#>      ( d --- string length )
ENDHSH  Terminate numeric conversion, drop the number being converted,
        leave the address of the conversion string and the length, ready
        for TYPE.

SIGN    ( n d --- d )
        Put sign of n (as a flag) in front of the conversion string.
        Drop the sign flag.

#       ( d --- d/base )
HASH    Generate next most significant digit in the conversion BASE,
        putting the digit in front of the conversion string.

#S      ( d --- dzero )
HASHS   Convert d to a numeric string using # until the result is zero.
        Leave the double result on the stack for #> to drop.

D.R     ( d width --- )
DDOTR   Print d on the output device in the current conversion base,
        with sign, right aligned in a field at least width wide.

D.      ( d --- )
DDOT    Print d on the output device in the current conversion base,
        with sign, in free format with trailing space.

.R      ( n width --- )
DOTR    Print n on the output device in the current conversion base,
        with sign, right aligned in a field at least width wide.

.       ( n --- )
DOT     Print n on the output device in the current conversion base,
        with sign, in free format with trailing space.

?       ( adr --- )
QDOT    Print signed word at adr, per DOT.

MESSAGE ( n --- )
MESS    If WARNING is 0, print "MESSAGE #n"; otherwise, print line n
        relative to screen 4, the line number may be negative.  Uses
        .LINE, but counter-adjusts to be relative to the real drive 0.
		
		In bif-c, add value of 2 for WARNING, for internal error message 
		strings.

(ABORT) ( anything --- nothing )        ( anything *** nothing )
IABORT  An indirection for ABORT, for ERROR, which may be modified
        carefully.

ERROR   ( anything line --- IN BLK )    ( anything *** nothing )
        ( anything --- nothing )        ( anything *** nothing ) WARNING < 0
        Prints out the last symbol scanned and MESSAGE number line.  If
        WARNING is less than zero, ABORTs through (ABORT), otherwise,
        clears the parameter stack, pushes the INput cursor and
        interpretaion BLK, and QUITs.

EDITOR  ( --- )                         in EDITOR               P
        Set the current interpretation vocabulary to EDITOR.

QSYNC   ( --- )                         in EDITOR
        Synchronize the ECB cursor with R#.

EBLK    ( --- vadr )                    in EDITOR
        USER variable containing the current editing block.

CURSOR  ( --- adr )                     in EDITOR
        Calculates the address of the edit cursor, R#, within the
        current editing block, bringing that block in if necessary.

QDUMP   ( adr --- )                     in EDITOR
        Dump the 256 bytes at adr to the screen memory, at the top half
        of the screen (bottom half of screen memory).

QARROW  ( c --- c )
        ( c --- 0 )
        Adjust the cursor according to the key passed.  If the key is a
        cursor control key, return 0; otherwise, leave the key
        unchanged.  The regular back-arrow is used for cursor movement,
        so the shifted back-arrow is used for destructive backspace.
        Also, the up arrow is used for cursor movement, so caret is not
        available without escaping.  See QUICK.


****          Definitions/Routines in BIF6.A and BIF6B.A:


(NUMBER)        ( d1 string --- d2 adr )
INUMB   Convert the text at string into a number, accumulating the
        result into d1, leaving adr pointing to the first character not
        converted.  If DPL is non-negative at entry, accumulates the
        number of characters converted into DPL.

NUMBER  ( ctstr --- d )
        Convert text at ctstr to a double integer, taking the 0 ERROR if
        the conversion is not valid.  If a decimal point is present,
        accumulate the count of digits to the decimal point's right into
        DPL (negative DPL at exit indicates single precision).  ctstr is
        a counted string -- the first byte at ctstr is the length of the
        string, but NUMBER ignores the count and expects a NUL
        terminator instead.

WORDPAD ( --- vadr )
WORDPD  The per-USER constant pointing to an intermediate
        buffer for text scanning.

WORD    ( c --- )
        Scan a string terminated by the character c or ASCII NUL out of
        input; store symbol at WORDPAD with leading count byte and
        trailing ASCII NUL.  Leading c are passed over, per ENCLOSE.
        Scans from BLK, or from TIB if BLK is zero.  May overwrite the
        numeric conversion pad, if really long (length > 31) symbols are
        scanned.

BS      ( --- c )
        The per-USER backspace constant.

EXPECT  ( buffer n --- )
        Get up to n-1 characters from the keyboard, storing at buffer
        and echoing, with backspace editing, quitting when a CR is read.
        Terminate it with a NUL.

QUERY   ( --- )
        EXPECT 128 (TWID) characters to TIB.

        ( --- )                                                 P
NUBLK   End interpretation of a line or screen, and/or prepare for a new
        block.  Note that the name of this definition is an empty
        string, so it matches on the terminating NUL in the terminal or
        block buffer.

FIND    ( namstr vocptr1 --- nfa vocptr2 )
        Search a vocabulary, and its parents, if necessary, for a
        definition called namstr.  namstr is a counted (leading count
        byte is ignored) string, vocptr1 is a pointer to a pointer to
        a vocabulary tree or subtree.  It will usually be the address of
        the per-USER variable ROOT or DROOT, but may be a pointer to a
        left or right link of an entry in the symbol tree.  nfa will be
        the name field address of the definition found, or a NULL.
        vocptr2 will be the pointer-pointer to the last vocabulary
        searched.  vocptr2 will be the last vocabulary searche.  See
        (FIND).

-DFIND  ( --- nfa vocptr )      { -DFIND name } typical input
DDFIND  Parse a word, then FIND, first in the definition vocabulary,
        then in the CONTEXT (interpretation) vocabulary, if necessary.
        Returns the address of the symbol table entry or a NULL, and the
        last vocabulary searched, per FIND.

-IFIND  ( --- nfa vocptr )      { -DFIND name } typical input
DIFIND  Same as -DFIND, except search the CONTEXT vocabulary first.

NAME,   ( --- ctStrPtr length )
NCOMMA  Store counted string at WORDPAD into dictionary, return HERE
        pointer and length of string.  Note that the count is not stored
        in the dictionary, but that the address returned will be the
        address to store the count at.  (The length of the names of
        definitions are stored after the actual names in the dictionary!)
		
		But in BIF-C, the lengths are stored with the strings, and the
		address returned points to where the counted string was stored.

FORE_MARK       ( --- )
FOREMK  Set forward reference bit in LATEST definition, if FOREWARD is
        non-NULL.

(INSTALL)       ( nfa vocptr --- )                              P
PINSTA  Install the header at nfa into the specified vocabulary, hiding
        (SMUDGEing) any existing definitions of the same name in that
        vocabulary. In BIF-6809, vocptr was a pointer to the parameter 
		field of the vocabulary, and we follow that in BIF-C v. 0.

0!      ( --- )
INULL   Store 0 word at NULL pointer (address 0).

?0      ( --- )
TNULL   Set warning to -1 and jmp to ERROR if the word at address 0
        (NULL pointer) is not 0.

QUICK   ( n --- )                       in EDITOR
        Quick and dirty editor; edits sectors, not screens.  See above
        description.

NODE.   ( nfa --- flag )
NDOT    ID. with some formatting, extra information useful for
        debugging, and a keyboard pause/abort test.  Returns flag less
        than 0 if BREAK key was pressed.

VISIT   ( defptr vocptr --- )
        Scan vocabulary at vocptr in ascending order, performing
        definition at defptr at every node.  defptr is an nfa, vocptr is
        the pfa of a vocabulary, per FIND and ROOT/DROOT.  The
        definition to be executed will have parameters of the same form
        as NDOT, doing something at a symbol tree node and leaving a
        termination flag.  VISIT checks for stack overflow and watches
        the termination flag between executions.  The VISITing
        definition may have other parameters, but if it changes the
        stack pointer from execution to execution VISIT will complain.

VLIST   ( --- )
        Alphabetically list the definitions in the current vocabulary.


****          Definitions/Routines in BIF7.A and BIF7B.A:


CREATE  ( --- )         { CREATE name } input
        Parse a name (length < 32 characters) and create a header,
        reporting first duplicate found in either the defining
        vocabulary or the context (interpreting) vocabulary.  (INSTALL)
        the header in the local vocabulary.

CONSTANT        ( n --- )
CONST   { value CONSTANT name } typical input
        CREATE a header, compile a call to XCON, compile the constant
        value.

VARIABLE        ( init --- )
VAR     { init VARIABLE name } typical input
        CREATE a header, compile a call to XVAR, compile the initial
        value init.

USER    ( ub --- )
USER    { uboffset USER name } typical input
        CREATE a header, compile a call to XUSER, compile the unsigned
        byte offset in the per-USER table.  The USER is entirely
        responsible for maintaining allocation!

:       ( --- )                                                 P
COLON   { : name sundry-activities ; } typical input
        If executing, record the data stack mark in CSP, CREATE a
        header, compile a call to XCOL, and set state to compile. (SCOMP
        is defined in this file.)  CONTEXT (interpretation) vocabulary
        is unchanged.

;       ( --- )                                                 P
SEMI    { : name sundry-activities ; } typical input
        ERROR check data stack against mark in CSP, compile ;S, unSMUDGE
        LATEST definition, and set state to interpretation.

."      ( --- )                                                 P
DOTQ    { ." something-to-be-printed " } typical input
        Use WORD to parse to trailing quote, if compiling, compile XDOTQ
        and string parsed, otherwise, TYPE string.

[COMPILE]       ( --- )                                         P
BCOMP   { [COMPILE] name } typical use
        -DFIND next WORD and COMPILE it, literally; used to compile
        immediate definitions.

INTERPRET       ( --- )
INTERP  Interpret or compile, according to STATE.  Searches words parsed
        in dictionary first, via -IFIND, then checks for valid NUMBER.
        Pushes or COMPILEs double literal if NUMBER leaves DPL
        non-negative.  ERROR checks the stack via ?STACK before
        returning to its caller.  Sensitive to COMPILE-ONLY bit in
        headers.

QUIT    ( anything *** nothing )
        Clear return stack.  Then INTERPRET and, if not compiling,
        prompt with OK, in infinite loop.

BIF     ( --- )                                                 P
        Makes BIF the current interpretation vocabulary.

ASSEMBLER       ( --- )                                         P
ASMBLR  Makes ASSEMBLER the current interpretation vocabulary.  Might
        ought not to be IMMEDIATE.

DEFINITIONS     ( --- )
DEFS    Makes the current interpretation vocabulary also the current
        defining vocabulary.

ABORT   ( anything --- nothing )        ( anything *** nothing )
        Clear parameter stack, intialize the NULL vector, set STATE to
        interpret and BASE to DECIMAL, return to input from terminal,
        restore DRIVE OFFSET to 0, set interpret and define vocabularies
        to BIF, print out "6809 BIF Vx.x", and finally, QUIT.  Used to
        force the system to a known state and return control to the
        standard INTERPRETer.

VOCABULARY      ( --- )         { VOCABULARY name } input
VOCAB   Create a vocabulary entry with a NULL local pointer, linked by
        the parent pointer to the current defining vocabulary.  The
        vocabulary parameter passed to the various searching routines is
        usually a pointer to the parameter field of a vocabulary.  That
        way, the root is functionally identically to a left or right
        link in a node or leaf, particularly for insertion.

(       ( --- )
PAREN   Parse out a comment and toss it away.  This is probably not
        useful, but it leaves the first 32 characters in WORDPAD.

DAD     ( nfa --- name linkadr flag )
        Search the parent vocabulary of the definition at nfa for nfa,
        returning the address of the first character of the definition's
        name, a pointer to the left or right link which links the
        definition in, and a flag indicating whether the definition is
        linked left or right.  ERROR if the definition can't be found.
        The return parameters are appropriate for REPEALing the
        definition.

REPEAL  ( --- )
        Remove the CURRENT/LATEST definition from the dictionary, from
        the vocabulary in which it is defined.  Updates CURRENT, alsoe
        updates DROOT or ROOT and clears FOREWARD, if appropriate.  If
        the CURRENT definition is in a closed forward block, repeals the
        entire block, so that forward references aren't pointing to
        trash.
		
		Except that I never got that last part written and working. So 
		you have to do that by hand. It does clear FOREWARD if FOREWARD 
		is pointing to the REPEALed definition.

FORGET  ( --- ) { FORGET name } input
        Parse out name of definition to FORGET to, -DFIND it, then
        REPEAL until it is removed from the dictionary.  Will not FORGET
        if definition is not found, if it is in a recursive block, or if
        it is below FENCE; the ERROR message will include the offending
        name.
		
		(Does it really?)


****                Definitions/Routines in BIFST.A


COLD    COLD boot.  Initializes the system variables, prunes the
        dictionary of everything beyond the initial FENCE, then WARM
        boots.

WARM    Resets stack areas and per-USER variables, clears the buffers,
        then yields control to BIF via ABORT.


****
Definitions on the SCREENs disk follow.  The vocabulary names are
abbreviated here under the definition names, A for ASSEMBLER, B for BIF,
U for UTILITIES, ^a for ^asm-util.

****                            SCREEN 0
Index to the screens disk.

****                            SCREEN 2
Title page and copyright notice.

****                            SCREEN 3
MON     ( --- )
-       Call the debugging monitor: SWI followed by a jmp [,y++], so
        that BIF can be continued.

After screen 2 creates MON, it updates FENCE to protect MON from WARM
boots.  Will load in the active vocabulary.

****                         SCREENs 4 & 5
Error and other Messages:
0: number conversion/unknown definition, no message text.
1: DATA STACK UNDERFLOW
2: DICTIONARY FULL
3: ADDRESS RESOLUTION ERROR for control structures
4: HIDES DEFINITION IN some vocabulary
5: NULL VECTOR WRITTEN
6: DISC RANGE? disk sector number out of range
7: DATA STACK OVERFLOW
8: DISC ERROR! of some sort -- is your drive door closed?
9: CAN'T EXECUTE A NULL!
10: CONTROL STACK UNDERFLOW
11: CONTROL STACK OVERFLOW
12: ARRAY REFERENCE OUT OF BOUNDS
13: ARRAY DIMENSION NOT VALID
14: NO PROCEDURE TO ENTER
15: ( was register error message for assembler )
16:
17: COMPILATION ONLY, USE IN DEFinition
18: EXECUTION ONLY do not use while compiling
19: CONDITIONALS NOT PAIRED where's your if/loop end statement?
20: DEFINITION INCOMPLETE often same as 18, but hit ;
21: IN PROTECTED DICTIONARY don't try to forget below FENCE.
22: USE ONLY WHEN LOADING
23: OFF CURRENT EDITING SCREEN an editor cursor problem
24: DECLARE VOCABULARY
25: DEFINITION NOT IN VOCABULARY
26: IN FORWARD BLOCK
27: ALLOCATION LIST CORRUPTED: LOST
28: CAN'T REDEFINE nul!  You tried to CREATE something without a name.
29: NOT FORWARD REFERENCE
30: ( was message about IMMEDIATE )
31:
32:
33: HAS INCORRECT ADDRESS MODE for 6809
34: HAS INCORRECT INDEX MODE for 6809
35: OPERAND NOT REGISTER in 6809
36: HAS ILLEGAL IMMEDIATE for 6809
37: PC OFFSET MUST BE ABSOLUTE pc-relative addressing error
38: ACCUMULATOR OFFSET REQUIRED for indexing mode
39: ILLEGAL MEMORY INDIRECTION for 6809
40: ILLEGAL INDEX BASE for 6809
41: ILLEGAL TARGET SPECIFIED for 6809 addressing mode or register
42: CAN'T STACK ON SELF for push/pull, try other stack pointer
43: DUPLICATE IN LIST of operands
44: REGISTER NOT STACK trying to push on a non-stack register?
45: EMPTY REGISTER LIST best supply some registers
46: IMMEDIATE OPERAND REQUIRED for 6809
47: REQUIRES CONDITION for control operator
48:
49: COMPILE-TIME STACK UNDERFLOW
50: COMPILE-TIME STACK OVERFLOW

****                            SCREEN 6

BYTE-DUMP       ( adr n --- )
U       Dump n bytes to output device, right adjusted in 4 character
        columns.  Field width is not big enough if BASE is six or less.

DUMP    ( adr n --- )
B       Formatted dump to output device, with ASCII interpretation.
        Hard coded to 4 bytes per line.

QLIST   ( n --- )
B       QDUMP a block/sector and set the cursor to the middle of the
        screen so the dump remains visible.

QINDEX  ( start end --- )
B       QLIST block/sectors from number start to end, inclusive.

L/SCR   ( --- n )
U       Calculate the number of terminal lines per disc screen at
        run-time.  Sixteen, at present.

ULIST   ( n --- flag )
U       List screen n, with line numbers in the current base, leave
        BREAK key flag.  Uses C/L, to automatically adjust for screen
        width (if C/L is set), but you may not want to use this
        definition if you set C/L to something besides 32 or 64.

****                            SCREEN 7

LIST    ( n --- )
B       ULIST screen n, line numbers in decimal.

INDEX   ( start end --- )
B       Print comment lines (line 0, and line 1 if C/L < 41) of screens
        from start to end.

TRIAD   ( n --- )
B       List a printer page full of screens to the printer, formatted by
        C/L.  Line and screen number are in current base.  Lists the
        group containing screen n, will print 2 screens if C/L is 32,
        three if C/L is 64.  (Two may not fit well.)

****                            SCREEN 8

HOME    ( --- )
U       Put the cursor at the (CoCo 2) CRT screen HOME position.

MID     ( --- )
U       Put the cursor 8 lines down the (CoCo 2) CRT screen.

CLS     ( --- )
B       Clear the (CoCo 2) CRT screen.

CAN-UP  ( adr -- adr )
U       Clear the UPDATE bit (MSB) for the buffer whose block word is at
        adr.  The characters in the buffer should be stored at adr+2.

W-BUF   ( adr --- adr )
U       Write the characters at adr+2 to the sector specified at adr,
        clear the UPDATE flag.

SAVE-BUF        ( adr --- adr )
U       W-BUF, if UPDATEd.

QSAVE   ( --- )
B       Save the PREViously edited buffer, if it was UPDATEd.

SAVE-BUFFERS    ( --- )
B       Write all buffers flagged for UPDATE, clear UPDATE bits.

QCAN    ( --- )
B       Cancel UPDATE of PREViously edited buffer.

****                            SCREEN 9

CANCEL-UPDATES  ( --- )
B       Cancel UPDATEs of all buffers.

RE-QUICK        ( --- )
B       Re-edit PREVious buffer.

.BUF    ( adr --- adr )
U       Dump buffer characters at adr+2, showing the sector number
        indicated at adr.

.BUFFERS        ( --- )
B       Dump all buffers, with block number, per .BUF.

.PREV   ( --- )
B       Dump contents and block number of PREVious buffer, per .BUF.

EDIT    ( n --- )
B       QUICK edit block n, showing the block number.

QPREV   ( --- )
B       QUICK edit the PREVious block.

****                           SCREEN 10

QOPY    ( src dest --- )
B       Move content of block/sector src to block dest.  BUG: Doesn't
        copy if src is already in a buffer (problem with LRU).

COPY    ( src dest --- )
B       Copy SCREEN src to SCREEN dest.  Uses QOPY, so you should
        EMPTY-BUFFERS before using COPY.

QBACK   ( start end --- )
B       Copy blocks from start to end to the next higher disc, at the
        same sector offset.

EEDIT   ( n --- )
B       Erase and then EDIT block n.

****                           SCREEN 11

RES-ERROR       ( --- )
U       ERROR #3

FORWARD ( --- )         { FORWARD name } input
B       Compile a forward reference header: CREATE, set FOREWARD if not
        already set, compile jmp to RES-ERROR, unSMUDGE header.

:RESOLVE        ( --- ) { :RESOLVE name } input                 P
A       If the characteristic of name is a jmp to RES-ERROR, make it
        LATEST, re-SMUDGE it, change jmp address to HERE; if the header
        of name is the base of the forward block, clear FOREWARD.
        Forward blocks should end with the definition of the first
        forward reference in the block, to maintain the block's
        integrity.  (However, the FOREWARD USER variable can be modified
        by hand, if necessary.)

:RES    ( --- )         { :RES name } input
B       Do ASSEMBLER's resolve, then compile jmp <XCOL and switch state
        to compile.

;RES    ( --- )                                                 P
B       ; but SMUDGE LATEST one more time.

****              SCREEN 11 does not continue LOADing!              ****

****                           SCREEN 12

PL      ( --- )
B       Print 80 ASCII characters starting with '!'.

PT      ( --- )
B       PL until any key is hit.

PTEST   ( --- )
B       PT, but send the output to the printer.

****                           SCREEN  13

SLIST   ( start end --- )
-       ULIST SCREENs to printer from start to end inclusive.

****                           SCREEN 14
This contains some experimental stuff that I was using to test my a
Sardis Technologies disk controller.

****                           SCREEN 15

NAME    ( cfa --- )
B       Convert the CFA on the stack to an nfa and ID. it.

NAMES   ( adr n --- )
B       NAME n icodes at adr.  Naively interprets anything as an icode.

****                           SCREEN 16
****                   The assembler starts here!                   ****

^asm-util       ( --- )
A       Vocabulary for assembler support stuff.  (Note that the name is
        in lower case and looks funny when editing until the cursor
        moves over it.)

DREG    ( n --- )       { n DREG name } input -> compile-time
^a      ( --- d ) -> run-time
        Define register double constants.  Most significant word is
        `RE', the index and operand encodings are masked into the least
        significant word.

xx      ( --- d ) high word is HEX 5245
A       The register double constants in hex:
        D  52458B00     A  52458608     B  52458509     PC 52458C05
        U  52454003     S  52456004     Y  52452002     X  52450001
        CC 5245EF0A     DP 5245EF0B
        Example: DP A EXG is exg dp,a

#       ( --- n )
A       Suffix constant for immediate values.  Becomes the high byte:
        4 # A LD is lda #4

DPREG   ( --- adr )
^a      DP register emulator for the assembler.  A per-USER variable at
        offset HEX 42, initialized to whatever the load-time DP is.

DPR     ( --- adr )
A       Push the current DPREG value, as a constant.  To use as an
        absolute address, push a 0 or -1 after.
        Example: DPR 7 + 0 JMP is jmp <7

SETDP   ( adr --- )
A       Set the DPREG value, masks the low byte of adr out.

****                           SCREEN 17

OFF,    (n b --- )
^a      Compile an index byte b with signed, constant, byte or word
        offset, n.  Sets bit 0 in the index byte if it compiles a word
        offset.

OP,     ( u --- )
^a      Compile opcode u.  Compiles 16 bits if high byte of u is
        non-zero.

ABS,    ( adr u1 u2 --- )
^a      Compile an absolute address mode (direct page or extended)
        op-code u1, oring u2 into u1 before compiling if the address is
        not in the direct page.

PCOFF   ( adr n1 --- n2 flag )
^a      Generate a pc-relative offset n2 from adr, adjusted by n1 bytes
        of op-code/index.  Flags true if offset fit in a byte, false if
        it required 16 bits.

?ABS    ( d --- adr flag )
^a      Convert high word of d to flag showing true if high word was 0
        or -1, false otherwise.  A 0 or -1 high word indicates an
        absolute address as an operand.
        Example: HEX .FF20 B OR is orb $FF20

PCR,    ( d b --- )
^a      ERROR if d is not absolute mode operand.  Calculate offset and
        compile index byte b and offset.

****                           SCREEN 18

Auto-indexing address mode double constants, in ASSEMBLER vocabulary:
-)      ( --- 4155.0082 )       ,-r
)++     ( --- 4155.0081 )       ,r++
)+      ( --- 4155.0080 )       ,r+
--)     ( --- 4155.0083 )       ,--r
        Example: )++ X , D ST is std ,x++

MASK,   ( b1 b2 --- )
^a      Compile the bit-or of the top two words's low bytes.

REG,    ( u b --- )
^a      Convert a register offset specified by u to its extension byte
        representation, mask in the index register and indirection
        specifier b, and compile the resulting index byte.

IXOFF,  ( n b --- )
^a      Generate the appropriate index extension byte for the constant
        offset n and indirection level specified, mask in the index
        register and indirection specifier b, and compile both the
        extension byte and the offset.  Handles zero and 5-bit offsets.

EI,     ( d b --- )
^a      Compile a (completely specified) extended-indirect extension
        byte b and the absolute address d.

****                           SCREEN 19

IX,     ( d n --- )
^a      Compile an index mode address operand.  n contains the index
        register and indirection level encoding, d contains the offset
        or auto-mode specification.  Zero offset must be explicit.  Does
        not block out unsupported [,r+] and [,-r] modes.

,       ( d1 --- d2 )
A       Convert indexable register d1 to index mode specifier d2.
        Examples: 0. X , B OR is orb ,x
                  A X , JMP is jmp a,x
                  TABLE 0 PC , X LEA is leax table,pcr

)       ( d1 --- d2 )
A       Convert indexable register, absolute address, or index operand
        d1 to memory indirect operand.  Note that this will NOT
        interfere with comments.
        Examples: TABLE 6 + 0 PC ) JMP is jmp [6,pcr]
                  )++ S ) JSR is jsr ,s++

****                           SCREEN 20

ACCM    ( n1 n2 n3 --- n4 )
^a      Convert op-code n1, register n2, and mask bits n3 to accumulator
        encoded op-code n4.  Used for encoding ACCM destination
        op-codes.

UNARY   ( u --- )               >--> compile-time
^a      { u UNARY name } input  >-/
        ( do dx --- ) indexed modes >-\
        ( d --- ) non-indexed modes >--> run-time
        Unary op-code compiler -- compiles an assembler of unary
        op-codes with op-code (u) and name.  Run-time parameters: d is
        the destination register or address, dx is the index
        mode/register, do is the offset/auto mode.
        Examples: A NEG is nega
                  7. U , ROR is ror 7,u

REG     ( d adr --- d u sz ) -- JSR
^a      ( d adr --- u sz )
        Encode binary destination register d into op-code from table at
        adr.  Table format is primary (byte), highest (byte), secondary
        (word) secondary (word) ....  Leave op-code u and size sz (-1 is
        word, 0 is byte) of register encoded.  Helps to reduce the
        complexity of the binary operators op-code map, see BINARY
        concerning constructing the tables.

****                           SCREEN 21

#,      ( n u sz --- )
^a      Compile an immediate op-code u with immediate operand n of size
        byte, if sz == 0, or word, ERROR if op-code is ST or JSR.

BINARY  ( ul b ub --- )                >--> compile-time
^a      { ul b ub BINARY name } input  >-/
        ( ds --- ) JSR                 >-\
        ( ds dd --- ) non-indexed mode >--> run-time
        ( do dx dd --- ) indexed mode  >-/
        Compile an assembler of binary operators, with primary op-code
        (accumulator form, any mode) ub, count of other codes (0, 1, or
        5) b, and optional list of other codes ul.  The list of other
        op-codes must be pushed on the stack in the order S, U, Y, X,
        and D (LD, ST, and CMP), or must be just the op-code for D (ADD
        and SUB).  Page escape codes must be included in the op-codes.
        Run-time operands: ds is the source, do is the source
        offset/auto mode, dx is the index mode/register, dd is the
        destination register. Example: 12 # D CMP is cmpd #12 -800. X )
        X LD is ldx [-800,x]

REG-REG ( b --- )       { b REG-REG name } input -> compile-time
^a      ( d1 d2 --- ) -> run-time
        Compile an assembler of register d1 to register d2 moves.
        Examples: D Y EXG is exg d,y
                  A CC TFR is tfr a,c

****                           SCREEN 22

REG-BITS        ( n --- vadr )
^a      1ARRAY of register bits for push/pull extension byte.  The
        Undefined slots set all bits to stabilize PACK.  Use the low
        word of a register specifier to index the array (see the DREG
        constants).

PACK    ( n dl n --- n b )
^       Pack register list dl into result byte b.  Terminates when the
        n, which is not the high word of a register specifier, is DUPed
        and compared to HEX 5245; thus, any word or double which won't
        be interpreted as a register specifier (see DREG) will terminate
        the list, including the stack hole.  ERRORs on attempt to push a
        stack register on itself.  May underflow the parameter
        stack if the stack hole is corrupted with HEX 5245, of course,
        but will not attempt to draw more than 8 doubles from the stack
        unless REG-BITS is corrupted.

MOVEM   ( b --- )       { b MOVEM name } input -> compile-time
^a      ( n dl d --- n ) -> run-time
        Compile a push or pull instruction assembler.  d is the stack
        register to push or pull.  See PACK.
        Example: D X Y U PSH is pshu d,x,y
        (But don't leave stray register specifiers on the stack!)

****                           SCREEN 23

BR      ( d1 d2 --- )
A       Assemble a branch on condition d2 to absolute address d1.
        Converts to PC relative, assembles a short branch if branch
        target is close enough.
        Example: LABEL 0 CCLR BR is bcc [LABEL]

DCOND   ( n --- )       { n DCOND name } input  -> compile-time
^a      ( --- d )
        Compile a branch condition constant; high word is HEX 434F.
        Always (AL), never (NV), and subroutine (SR) are provided as
        DCONDs.
        Example: ' BMUL CFA 0 AL BR is bra BMUL

CC-IMM  ( b --- )       { b CC-IMM name } -> compile-time
^a      ( d --- ) -> run-time
        Compile ORCC, ANDCC, EORCC, or CWAI assemblers.  The assemblers
        will ERROR if the operand is not immediate.
        Example: HEX EF # CWAI is cwai #$EF

IMPLY   ( b --- )       { b IMPLY name } input >--> compile-time
^a      ( --- ) run-time
        Compile assemblers of implicit operand instructions.
        Example: NOP is nop

****        The next two SCREENs contain op-code assemblers.        ****
See the compilers for run-time descriptions.  The odd organization keeps
the trees balanced.  The assemblers, or, in other words, the mnemonics,
are in the ASSEMBLER vocabulary.

****                           SCREEN 24

BINARYs LD ST and CMP with their associated 16-bit register op-code
        lists.
MOVEMs PUL PSH          UNARYs ROR ROL          IMPLYs RTS RTI
BINARY SBC              DCOND SR (subroutine)   REG-REG TFR
UNARY TST               BINARY SUB with D
IMPLYs SWI2 SWI3 SWI SYNC                       BINARYs AND ADC
UNARYs ASL ASR          BINARY ADD with D       IMPLY ABX
DCOND CS                UNARYs COM CLR          DCOND AL (always)
BINARY BIT              UNARY DEC               IMPLY DAA
DCONDs HI MI EQ GE      REG-REG EXG             UNARY INC
BINARY JSR              UNARY JMP               BINARY EOR
DCONDs GT HS            IMPLY NOP               DCONDS LS PL

****                           SCREEN 25

UNARYs LSR LSL          DCONDs LT NE            IMPLY MUL
UNARY NEG               BINARY OR               CC-IMM ORCC
DONCD NV (never)        IMPLY SEX (blush)       CC-IMMs ANDCC CWAI
DCONDs VC VS CCLR (Carry CLeaR)

EA-IX   ( n --- vadr )
^a      1ARRAY of translations from register (DREG) to LEA arguments.

LEA     ( do dx dd --- )
A       Assembler for LEA instructions.  do is the offset/auto mode, dx
        is the source index register, dr is the destination index
        register.
        Example: D Y , X LEA is leax d,y

DCONDs LE LO

****                           SCREEN 26

[CD]    ( --- dcfa )     { [CD] name } input                    P
A       Produce the CFA of the following definition header, for use as a
        jump or indexing target.  If compiling, causes the code address
        to be compiled as a double literal; otherwise, pushes the cfa as
        a double, so the assemblers can use it for addressing.

& ! ^   ( n1 n2 --- n3 )
A       Aliases for AND OR and XOR for the assembler vocabulary.

NEXT    ( --- )
A       Assembler the NEXT instruction, jmp [,y++].

****    The assembler control constructs are patterned after FORTH
control constructs, but test the Condition Code register.
****

****                           SCREEN 27

INVERTCC        ( dcond --- ~dcond )
^a      Invert the assembler branch condition (double word) on top of
        stack.

LIF     ( dcond --- daddr )
A       Mark HERE as a double with the address in the low word and HEX
        4146 in the high word.  Assemble a long branch on the inverse of
        the condition given, and leave the mark.  Temporarily set the
        branch address to the RES-ERROR routine.

IF      ( dcond --- daddr )
A       Same as LIF, but assembles short branch with 0 offset.

****                           SCREEN 28

FILL-IN ( dadr --- )
^a      Resolve offset of branch at mark to HERE, handle two, three, and
        four byte branches.

****                           SCREEN 29

ELSE    ( daddr1 --- daddr2 )
A       ERROR check the mark daddr1, mark HERE and assemble short branch
        always, via IF, and FILL-IN the previously marked IF or LIF.

LELSE   ( daddr1 --- daddr2 )
A       Same as ELSE except mark and assemble long branch always via
        LIF.

ENDIF   ( daddr --- )
A       ERROR check the mark, and resolve the IF or LIF.

BEGIN   ( --- daddr )
A       Mark indefinite loop beginning with HERE.  High word of mark is
        HEX 4142.

UNTIL   ( daddr dcond --- )
A       ERROR if daddr is not BEGIN mark; assemble branch on inverse of
        condition dcond to address marked in daddr.

WHILE   ( daddr dcond --- adr daddr )
A       ERROR if daddr is not BEGIN mark; assemble forward branch on
        inverse of condition dcond, leave BEGIN address on stack and
        extend mark with WHILE address and mark, HEX 4157.

REPEAT  ( adr daddr --- )
A       ERROR if not WHILE mark, assemble a branch to the BEGIN address
        and FILL-IN the WHILE address.

LWHILE  ( daddr dcond --- adr daddr )
A       Forced long branch version of WHILE.

****                           SCREEN 30

:ASM    ( --- )
A       CREATE a header and store the parameter stack pointer in CSP to
        mark the stack for assembler control construct and other errors.

;ASM    ( --- )
A       ERROR check CSP and un-smudge the definion.  NEXT must be
        explicitly assembled.

I-CODE  ( --- )
A       Shift to high-level compiling.  (Assembles jmp <XCOL, changes
        state to compiling, changes interpretation vocabulary to
        definition vocabulary.)

MACHINE ( --- )                                                 P
A       Shift to assembly language.  (Compiles (MACHINE), changes state
        to interpretation, sets interpretation vocabulary to assembler.)

****                           SCREEN 32
                             Some Doubles

D!      ( d adr --- )
B       Store double d at adr.

D@      ( adr --- d )
B       Fetch double (two words) at adr.

DOVER   ( d1 d2 --- d1 d2 d1 )
B       Copy the second double (bytes 4-7) on the stack to the top.

DSWAP   ( d1 d2 --- d2 d1 )
B       Swap the top two doubles (bytes 0-3 with bytes 4-7).

****                           SCREEN 64

        This is an example showing use of the dictionary to associate
pairs, from one of the textbooks I have.  I apologize to the source for
not giving proper credit, but I can't find it.  It is included to show
use of DOES> and to show how having the symbol table handy at run-time
can be taken advantage of.  It builds pairs of objects linked to each
other such that typing one in results in printing the other out.


*******************************************************************************
                      Some Thoughts and Comments:


Hey, it's not a professional package, so I can put this here if I want!

One of the problems with BIF is the power of the 6809.  It is all too
easy to use 6809 instructions instead of icodes.  This means that the
6809 architecture gets woven into BIF, as mentioned at the end of the
discussion on the virtual machine.

BIF can probably be made to conform with one of the standards by moving
the virtual machine routines to their associated definitions (XCOLON to
COLON, XVAR to VARIABLE, etc.) and by making all code fields three-byte
jumps (JSRs).  Direct threading will probably not be a problem, as long
as code fields are uniform in size.

The constant shifting between modes which I have done makes a built-in
debugger more complex, as well.  One specific example is that using a
macro instead of a jump to a NEXT inner interpreter makes debugging more
complex.  If there is an inner interpreter, and if the low level
routines are known to be error free, the debugger can simply be a jump
inserted in the NEXT routine.  Use of a macro forces the debugger to be
sensitive to the 6809 architecture, and requires either use of the SWI
method (which can't be used in ROM), CPU emulation, or external
breakpoint/single-step hardware.  The latter method is more complete,
but inserting a debugging routine in the inner interpreter is often all
that is necessary.

A possible inner interpreter for a direct threaded FORTH (could be
located in the direct page):

        NEXT    ldx ,y++                8~
                jmp ,x                  3~      14~     (w/ jmp <NEXT)

Or for indirect threading:
        NEXT    ldx ,y++                8~
                jmp [,x]                6~      17~     (w/ jmp <NEXT)

Compared to BIF:
                jmp [,y++]              9~

The apparent disadvantages of the above are at least partially offset by
the fact that X will contain the CFA on entry to the characteristic
routines.  In other words, X can substitute for W, and there is no need
to store the CFA of the executing low level routine in an external
register (on the stack, in the case of BIF).  Showing how this affects
XCOL, for direct threading:

        someDEF jmp XCOL                4~
        . . .
        XCOL    pshs y                  7~
                leay 3,x                5~
                jmp <next               3~      19~, total 33~

For indirect threading:

        someDEF fdb XCOL                0~
        . . .
        XCOL    pshs y                  7~
                leay 2,x                5~
                jmp <NEXT               3~      15~, total 32~

Compared to BIF:
        someDEF jsr <XCOL               7~
        . . .
        XCOL    ldx ,s                  5~
                sty ,s                  6~
                tfr x,y (leay ,x)       6~ (4~)
                jmp [,y++]              9~      33~, total 42~

SURPRISED?  I was.  Of course, the characteristic routines must be a
little careful to use or save X before they clobber it, but that isn't
as difficult as it might seem.

The direct page might still be used to locate the per-USER table, or
might even contain it.  At first glance, it would appear too expensive
to offset the DP register with a variable index.  But compare the
following to the code in BIF:

        XUSER   tfr dp,a                6~
                ldb [,s++]              10~     (stored as byte offset)
                pshu d                  7~      (there's the address)
                jmp [,y++]              9~      32~ compared to 34~

If X is used for the temporary W register as in the indirect threaded
inner interpreter example above, we can get the following, which speaks
for itself:

        XUSER   tfr dp,a                6~
                clrb                    2~      (showing word offset, )
                addd 2,x                7~      (byte would be shorter)
                pshu d                  7~
                jmp <NEXT               3~      25~

Ah, experience.  What we have to go through to get it!

The key to FORTH and its dialects is found in ;CODE and DOES>.  By
providing both characteristic behaviour and data allocation, FORTH words
(symbols/definitions) are primitive objects.  A full object-oriented
language could be generated with FORTH, but then you would probably have
SMALLTALK!.  A standard compiling language keeps the symbol table, its
data, and the code that accesses it entirely separate, and wastes a lot
of code space doing so.  Professional FORTH systems can strip the symbol
table out of compiled applications, if necessary, but the symbol table
is available at run-time until the programmer is satisfied that his
program is bug-free.  Moreover, the programmer has access to the same
library used by the language, which is usually not the case with
compiled languages, even with C.

A careful examination of the overhead in FORTH shows that it is
approximately the same as the overhead in a good C compiler.  While it
would appear that constantly moving stuff on and off the stack would be
a hindrance to progress, a second look reveals that the accumulator
bottleneck requires this kind of movement.  I wish I had time and
facilities to examine this specific question in relation to a large
register set.

I sometimes wonder if management paranoia (PROTECT OUR INTELLECTUAL
PROPERTY!) is the primary reason FORTH, LISP, and SMALLTALK have not
entirely supplanted the compiled languages.  If so, why is management
willing to hide, protect, and hang on to code, but not willing to hang
on to the engineers in whose brains the technology really resides?  Or
in the converse, if management can see that it is sometimes necessary to
let people go, why can't they see that there are some things that are
not worth the cost of trying to protect their tools from?  And why can't
they see that a intellectual property stolen by copying still requires a
large investment in somebody's time to learn to use it?  Why doesn't
public domain code get used?  Because it costs better than an order of
magnitude more to learn how to use it than it does to get it.

