FLOAT
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
representation.
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
complement).
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
number.
-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
FTR(FEXP(FLDI(1,1),4))=16.
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
large.
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
number.
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
FPwork=new
...routines use "new" work area; will not affect "old"
FPwork=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
FPSetup(new)
...routines use "new" work area; will not affect "old"
FPSetup(old)
Loading the RAM, calling FPSetup, and the (shorter) work area format
are the only changes from the assembly coded routines.