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.