FLOAT is a floating-point package  for the Alto, intended for  use with
BCPL.  (It uses standard Alto microcode -- no special  instructions are
needed.) A microcoded version  is also available, and is  documented in
the last section.   There are 32 floating-point  accumulators, numbered
0-31.   These  accumulators may  be  loaded, stored,  operated  on, and
tested  with the  operations provided  in this  package.   'Storing' an
accumulator means  converting it to  a 2-word packed  format (described
below) and storing the packed form.

In the discussion below, 'ARG' means: if the 16-bit value is  less than
the number of accumulators, then use the contents of the accumulator of
that number.  Otherwise, the 16-bit value is assumed to be a pointer to
a packed floating-point number.

All of  the functions listed  below that do  not have "==>"  after them
return their first argument as their value.

1. Floating point routines

     FLD (acnum,arg)           Load  the  specified   accumulator  from
                               source specified by arg. See above for a
                               definition of 'arg'.

     FST (acnum, ptr-to-num)   Store  the contents  of  the accumulator
                               into  a  2-word  packed  floating  point
                               format.  Error if exponent is  too large
                               or   small  to   fit  into   the  packed

     FTR (acnum) ==> integer   Truncate  the floating  point  number in
                               the accumulator  and return  the integer
                               value.   FTR applied  to  an accumulator
                               containing 1.5  is 1; to  one containing
                               -1.5 is -1. Error if number in ac cannot
                               fit in an integer representation.

     FLDI (acnum,integer)      Load-immediate  of  an  accumulator with
                               the   integer   contents   (signed   2's

     FNEG (acnum)              Negate the contents of the accumulator.

     FAD (acnum,arg)           Add the number in the accumulator to the
                               number  specified by  arg and  leave the
                               result in the accumulator. See above for
                               a definition of 'arg'.

     FSB (acnum,arg)           Subtract the  number specified  by 'arg'

                   Copyright Xerox Corporation 1979

FLOAT                      December 26, 1977                          2

                               from the number in the  accumulator, and
                               leave the result in the accumulator.

     FML (acnum,arg) [ also FMP ]   Multiply  the  number  specified by
                               'arg' by the number in  the accumulator,
                               and leave the result in the ac.

     FDV (acnum,arg)           Divide the  contents of  the accumulator
                               by  the  number  specified  by  arg, and
                               leave  the result  in the  ac.  Error if
                               attempt to divide by zero.

     FCM (acnum,arg) ==> integer Compare the number in the ac  with the
                               number specified by 'arg'. Return
               -1 IF ARG1 < ARG2
                0 IF ARG1 = ARG2
                1 IF ARG1 > ARG2

     FSN (acnum) ==> integer   Return  the sign  of the  floating point
               -1 if sign negative
               0 if value is exactly 0 (quick test!)
               1 if sign positive and number non-zero

     FEXP(acnum,increment)     Adds 'increment' to the exponent  of the
                               specified accumulator.  The  exponent is
                               a       binary        power.        Thus

     FLDV (acnum,ptr-to-vec)   Read  the  4-element  vector   into  the
                               internal  representation  of  a floating
                               point number.

     FSTV (acnum,ptr-to-vector)Write the accumulator into the 4-element
                               vector in internal representation.

2. Double precision fixed point

There  are also  some  functions for  dealing with  2-word  fixed point
numbers.  The functions are chosen to be helpful to DDA scan-converters
and the like.

     FSTDP(ac,ptr-to-num)      Truncates the  contents of  the floating
                               point   ac  and   stores  it   into  the
                               specified    double-precision    number.
                               First word of the number is  the integer
                               part,   second   is    fraction.   Two's
                               complement.    Error  if   exponent  too

     FLDDP(ac,ptr-to-num)      Loads floating point ac from  dp number.
                               Same   conventions   for   integer   and
                               fractional part as FSTDP.

     DPAD(a,b) => ip           a and b are both pointers to dp numbers.
                               The dp sum  is formed, and stored  in a.

FLOAT                      December 26, 1977                          3

                               Result  is  the  integer  part   of  the

     DPSB(a,b) => ip           Same as DPAD, but subtraction.

     DPSHR(a) => ip            Shift  a  double-precision  number right
                               one bit, and return the integer part.

3. Format of a packed floating point number

  structure FP: [
      sign  bit 1     //1 if negative.
      expon bit 8    //excess 128 format (complemented if number <0)
      mantissa1 bit 7 //High order 7 bits of mantissa
      mantissa2 bit 16 //Low order 16 bits of mantissa

Note this format  permits packed numbers to  be tested for sign,  to be
compared (by comparing first words first), to be tested for zero (first
word zero is sufficient), and (with some care) to be complemented.

4. Saving and Restoring Work Area

FLOAT  has a  compiled-in work  area for  storing contents  of floating
accumulators, etc.  The  static FPwork points  to this area.  The first
word of the area (i.e. FPwork!0)  is its length and the second  word is
the number of  floating point accumulators  provided in the  area.  The
routines use whatever  pointer is currently  in FPwork for  the storage
area.  Thus, the accumulators may be "saved" and "restored" simply by:
        let old=FPwork
        let new=vec enough; new!1=old!1 //Copy AC count
        ...routines use "new" work area; will not affect "old"
This mechanism also lets you set  up your own area, with any  number of
accumulators.   The  length  of  work  area  required  is  4*(number of
accumulators)+constant.  (The constant  may change when bugs  are fixed
in the floating point routines.   As a result, you should  calculate it
from  the   compiled-in  work   area  as   follows:  constant←FPwork!0-
4*FPwork!1.) It  is not  essential that the  length word  (FPwork!0) be
exact for the routines to work.

5. Errors

If you wish to capture errors, put the address of a BCPL  subroutine in
the static FPerrprint.  The routine will be called with one parameter:
     0 Exponent too large -- FTR
     1 Exponent too large -- FST
     2 Dividing by zero -- FDV
     3 Ac number out of range (any routine)
     4 Exponent too large -- FSTDP

FLOAT                      December 26, 1977                          4

The  result of  the error  routine  is returned  as the  result  of the
offending call to the floating point package.

6. Floating point microcode

A  microcoded version  of  the FLOAT  package is  also  available.  The
microcode is  from four  to six  times faster  than the  assembly code.
Execution times are about 80 microseconds for multiply and  divide, and
40 microseconds for  addition and subtraction.  The  file MicroFloat.DM
is  a dump-format  file containing  MicroFloat.BR  and MicroFloatMC.BR.
These  modules  should be  loaded  with your  program,  along  with the
LoadRam procedure, available  separately as LoadRam.BR.   The microcode
RAM  must   be  loaded  with   the  appropriate  microcode.    This  is
accomplished  by calling  LoadRam(MicroFloatRamImage) After  this call,
the  memory  space  used  for  MicroFloatMC.BR  and  LoadRam.BR  can be
released.  Microfloat.BR  must remain  resident, but  it only  takes up
about 60  words.  The floating  point routines can  also be  invoked as
single assembly code instructrions, with op codes 70001  through 70021.
The correspondence  between op codes  and floating point  operations is
documented in MicroFloat.ASM.

In  contrast to  the  assembly coded  version, the  microcode  does not
allocate any memory work space,  and any number of accumulators  may be
used.  Four words of memory  are needed for each accumulator,  and this
memory space MUST be provided by the user by calling FPSetup(workArea),
where workArea is the block of memory to be used for  mainintaining the
ACS, and  workArea!0 is  the number  of accumulators  to be  used.  The
length  of workArea  must  be at  least (4*numACs)+1  words  long.  The
contents  of  workArea  are  not  re-iitialized,  so  that   reusing  a
previously used work area will have the effect of restoring  the values
of the ACs to their previous  state.  The static FPwork will be  set to
the current workArea.  So, "save" and "restore" the accumulators by:
        let old=FPwork
        let new=vec (4*numACs)+1; new!0=numACs
        ...routines use "new" work area; will not affect "old"

Loading the RAM,  calling FPSetup, and  the (shorter) work  area format
are the only changes from the assembly coded routines.