*----------------------------------------------------------- Title[DMesaFloat.mc...June 12, 1982 11:44 AM...Taft]; * Mesa floating point operations *----------------------------------------------------------- % CONTENTS, by order of alpha byte value FAdd (alpha=20B) Floating add FSub (alpha=21B) Floating subtract FMul (alpha=22B) Floating multiply FDiv (alpha=23B) Floating divide FComp (alpha=24B) Floating compare Fix (alpha=25B) Fix to LONG INTEGER Float (alpha=26B) Float a LONG INTEGER FixI (alpha=27B) Fix to INTEGER FixC (alpha=30B) Fix to CARDINAL FSticky (alpha=31B) Read and set Inexact Result sticky flag and enable FRem (alpha=32b) (Floating remainder unimplemented) Round (alpha=33B) Round to LONG INTEGER RoundI (alpha=34B) Round to INTEGER RoundC (alpha=35B) Round to CARDINAL FSqRt (alpha=36B) (Square root unimplemented) FSc (alpha=37B) Floating scale *----------------------------------------------------------- * Conventions *----------------------------------------------------------- IEEE standard floating point number representation (single-precision): bit 0 sign (1 = negative) bits 1-8 excess-127 exponent (0 = true zero if fraction = 0, else denormalized; 377 = infinity or Not-a-Number) bits 9-31 fraction, implicitly preceded by "1." if nonzero and normalized Internal (unpacked) representation, for argument 1 (argument 2 is similar): ExpSign1 [0] = 0, [1:8] = excess-128 exponent, [9:12] = 0, [13:14] undefined, [15] sign (1 = negative) Frac1H high 16 bits of fraction; if number nonzero, includes explicit "1" in bit 0 and binary point between bits 0 and 1 Frac1L low 8 bits of fraction left-justified, followed by non-significant bits and sticky bit Timings are for cases involving normalized nonzero numeric operands. Where expressed in microseconds, a 64-ns cycle time is assumed (clock = 32ns). Note: at all MiscTable entries, T contains the top-of-stack and StkP has been incremented. % * Local R-register usage: SetRMRegion[BBRegs]; * Overlay BitBlt registers RVN[ExpSign1]; * Exponent and sign of argument 1 RVN[Frac1H]; * Fraction of argument 1 (high part) RVN[Frac1L]; * (low part) RVN[ExpSign2]; * Argument 2 ... RVN[Frac2H]; RVN[Frac2L]; RVN[FTemp0]; * Temporaries RVN[FTemp1]; RVN[FTemp2]; * Alto mode: OTPReg preserves the MISC alpha byte (in bits 6:13), in case we * need to trap. OTPReg = 4*alpha if entry point 0 or 1 was taken, * 4*alpha+1 if entry point 2. * Sticky is permanently dedicated to holding the Inexact Result sticky flag * and enable bit: * Sticky[0]=1 => trap enabled * Sticky[15]=1 => Inexact Result has occurred *----------------------------------------------------------- FloatingPointPresent: * Returns T=2 if floating point microcode is present, 0 otherwise. *----------------------------------------------------------- Subroutine; T← 2C, Return; TopLevel; KnowRBase[RTemp0]; *----------------------------------------------------------- * Unimplemented operations *----------------------------------------------------------- MiscTable[32], Branch[FloatTrap]; * FRem MiscTable[36], Branch[FloatTrap]; * Undefined :If[AltoMode]; ********** Alto version ********** *----------------------------------------------------------- FSticky: MiscTable[31], * Sticky flags * new: StickyFlags ← Pop[]; Push[stickyFlags]; stickyFlags← new; *----------------------------------------------------------- Sticky← T, Q← Sticky; Stack-1← Q, IFUNext0; :Else; ******** PrincOps version ******** *----------------------------------------------------------- FSticky: MiscTable[31], * Sticky flags * new: StickyFlags ← Pop[]; Push[stickyFlags]; stickyFlags← new; *----------------------------------------------------------- RBase← RBase[Sticky]; Sticky← T, Q← Sticky; Stack-1← Q, IFUNext0; :EndIf; ********************************** *----------------------------------------------------------- FSub: MiscTable[21], * Floating subtract * a, b: REAL; * b ← PopLong[]; a ← PopLong[]; PushLong[a-b]; * Timing: same as FAdd. *----------------------------------------------------------- RBase← RBase[FTemp0], StkP-2, SCall[FUnPack2]; ExpSign2← (ExpSign2)+1, Branch[FAddZeroR]; * Flip sign of arg 2 and add ExpSign2← (ExpSign2)+1, Branch[FAddNonZero]; *----------------------------------------------------------- FAdd: MiscTable[20], * Floating add * a, b: REAL; * b ← PopLong[]; a ← PopLong[]; PushLong[a+b]; * Timing: 34 cycles, +[7..9] if operand exponents differ, +5 if round, * + one of the following: * signs equal: +2, +3 more if result exponent > max(arg1, arg2) exponent. * signs unequal: +8, +3 more if result sign # arg1 sign, * + 2*((max(arg1 exponent, arg2 exponent) - result exponent) mod 16). * Typical case involving unnormalization but no renormalization or rounding: * 49 cycles or ~ 3.1 microseconds *----------------------------------------------------------- RBase← RBase[FTemp0], StkP-2, SCall[FUnPack2]; FAddZeroR: PD← (Stack&+2)+(Stack&+2), Branch[FAddZero]; * +1: at least one arg is zero * Difference between exponents is the amount of unnormalization required. * The low 7 bits of ExpSign1 contain either 4 or 5, whereas the low 7 bits * of ExpSign2 contain 0, 1, or 2. Thus subtracting ExpSign2 from * ExpSign1 cannot cause a carry out of the low 7 bits. * Furthermore, the low bit gets the xor of the two signs, useful later * when determining whether to add or subtract the fractions. FAddNonZero: T← ExpSign1; ExpSign2← T← T-(Q← ExpSign2); FTemp1← A0, Q RSH 1; T← T+T, DblBranch[UnNorm1, UnNorm2, Carry']; * Un-normalize operand 1. T[0:7] has negative of right-shift count. UnNorm1: ExpSign1← (B← Q) LSH 1, Branch[.+2, R even]; * Result exponent is Exp2 ExpSign1← (ExpSign1)+1; * But preserve Sign1 T← T+(LShift[20, 10]C); T← T+(LShift[20, 10]C), Branch[UnNorm1le20, Carry]; T← T+(LShift[20, 10]C), Branch[UnNorm1le40, Carry]; * Exponents differ by more than 40. * Just zero operand 1, but be sure to set the sticky bit. Frac1L← 1C; ZeroFrac1H: Frac1H← A0, Branch[UnNormDone]; * Exponent difference IN [1..20]. Let n = the difference. * T[0:7] now has 40 - n, i.e., IN [20..37], so SHA=R, SHB=T. * This is correct shift control for LCY[R, T, 20-n] = RCY[T, R, n] UnNorm1le20: T← Frac1L, ShC← T; PD← ShiftNoMask[FTemp1]; * PD← RCY[Frac1L, 0, [1..20]] T← Frac1H, FreezeBC; Frac1L← ShiftNoMask[Frac1L], * Frac1L← RCY[Frac1H, Frac1L, [1..20]] Branch[.+2, ALU=0]; * Test bits shifted out of Frac1L Frac1L← (Frac1L) OR (1C); * Nonzero bits lost, set sticky bit T← A0, Q← Frac2L; Frac1H← ShiftNoMask[Frac1H], * Frac1H← RCY[0, Frac1H, [1..20]] Branch[UnNormDone1]; * FAdd/FSub (cont'd) * Exponent difference IN [21..40]. Let n = the difference. * T[0:7] now has 60 - n, i.e., IN [20..37], so SHA=R, SHB=T. * This is correct shift control for LCY[R, T, 40-n] = RCY[T, R, n-20] UnNorm1le40: T← Frac1H, ShC← T; T← ShiftNoMask[FTemp1]; * T← RCY[Frac1H, 0, [1..20]] PD← T OR (Frac1L); * Bits lost from Frac1H and Frac1L T← A0, FreezeBC; Frac1L← ShiftNoMask[Frac1H], * Frac1L← RCY[0, Frac1H, [1..20]] Branch[ZeroFrac1H, ALU=0]; Frac1L← (Frac1L) OR (1C), * Nonzero bits lost, set sticky bit Branch[ZeroFrac1H]; * Un-normalize operand 2. T[0:7] has right-shift count, and T[8:15] is IN [0..12]. UnNorm2: T← (12S)-T; * Negate count; ensure no borrow by ALU[8:15] T← T+(LShift[20, 10]C), Branch[UnNormDone, Carry]; * Branch if exponents equal T← T+(LShift[20, 10]C), Branch[UnNorm2le20, Carry]; T← T+(LShift[20, 10]C), Branch[UnNorm2le40, Carry]; * Exponents differ by more than 40. * Just zero operand 2, but be sure to set the sticky bit. Frac2L← 1C; ZeroFrac2H: T← Frac2H← A0, Branch[UnNormDone]; * Exponent difference IN [1..20]. Let n = the difference. * T[0:7] now has 40 - n, i.e., IN [20..37], so SHA=R, SHB=T. * This is correct shift control for LCY[R, T, 20-n] = RCY[T, R, n] UnNorm2le20: T← Frac2L, ShC← T; PD← ShiftNoMask[FTemp1]; * PD← RCY[Frac2L, 0, [1..20]] T← Frac2H, FreezeBC; Frac2L← ShiftNoMask[Frac2L], * Frac2L← RCY[Frac2H, Frac2L, [1..20]] Branch[.+2, ALU=0]; * Test bits shifted out of Frac2L Frac2L← (Frac2L) OR (1C); * Nonzero bits lost, set sticky bit T← A0, Q← Frac2L; T← Frac2H← ShiftNoMask[Frac2H], * Frac2H← RCY[0, Frac2H, [1..20]] Branch[UnNormDone2]; * Exponent difference IN [21..40]. Let n = the difference. * T[0:7] now has 60 - n, i.e., IN [20..37], so SHA=R, SHB=T. * This is correct shift control for LCY[R, T, 40-n] = RCY[T, R, n-20] UnNorm2le40: T← Frac2H, ShC← T; T← ShiftNoMask[FTemp1]; * T← RCY[Frac2H, 0, [1..20]] PD← T OR (Frac2L); * Bits lost from Frac2H and Frac2L T← A0, FreezeBC; Frac2L← ShiftNoMask[Frac2H], * Frac1L← RCY[0, Frac1H, [1..20]] Branch[ZeroFrac2H, ALU=0]; Frac2L← (Frac2L) OR (1C), * Nonzero bits lost, set sticky bit Branch[ZeroFrac2H]; * Now decide whether fractions are to be added or subtracted. * ExpSign2[15] remembers the xor of the signs. UnNormDone: Q← Frac2L; UnNormDone1: T← Frac2H; UnNormDone2: ExpSign2, DblBranch[SubFractions, AddFractions, R odd]; * Subtract if signs differ * FAdd/FSub (cont'd) * Signs equal, add fractions. T = Frac2H, Q = Frac2L. AddFractions: Frac1L← (Frac1L)+Q; Frac1H← T← (Frac1H)+T, XorSavedCarry; PD← (Frac1L) AND (377C), Branch[FRePackNZ1, Carry']; * If carry out of high result, must normalize right 1 position. * Need not restore leading "1", since rounding cannot cause a carry into this * position, and the leading bit is otherwise ignored during repacking. Frac1H← (Frac1H) RSH 1; Frac1L← RCY[T, Frac1L, 1], Branch[.+2, R even]; Frac1L← (Frac1L) OR (1C); * Preserve sticky bit ExpSign1← (ExpSign1)+(LShift[1, 7]C), Branch[FRePackNonzero]; * Signs differ, subtract fractions. T = Frac2H, Q = Frac2L. SubFractions: Frac1L← (Frac1L)-Q; T← (Frac1H)-T-1, XorSavedCarry; Frac1H← A0, FreezeBC, Branch[Normalize, Carry]; * If carry, Frac1 was >= Frac2, so result sign is Sign1. * If no carry, sign of the result changed. Must negate fraction and * complement sign to restore sign-magnitude representation. ExpSign1← (ExpSign1)+1; Frac1L← (0S)-(Frac1L); T← (Frac1H)-T-1, XorSavedCarry, Branch[Normalize]; * Add/Subtract with zeroes: * One or both of the operands is zero. ALU = (high word of arg1) LSH 1. This is * zero iff arg1 is zero (note that we don't need to worry about denormalized numbers, * since they have been filtered out already). * StkP has been advanced to point to high word of arg2. FAddZero: T← (Stack&-1)+(Q← Stack&-1), * T← (high word of arg2) LSH 1 Branch[FAddArg2Zero, ALU#0]; * arg1#0 => arg2=0 Cnt← Stack&-1, * Cnt← low word of arg2 Branch[FAddArg1Zero, ALU#0]; * arg2#0 => arg1=0 * Both args are zero: result is -0 if both args negative, else +0. StackT← (StackT) AND Q, IFUNext2; * Arg 1 is zero and arg 2 nonzero: result is arg 2. * Note: must re-pack sign explicitly, since FSub might have flipped it. FAddArg1Zero: T← RCY[ExpSign2, T, 1]; * Insert Sign2 into high result Stack&-1← T; Stack&+1← Cnt, IFUNext0; * Arg 2 is zero and arg 1 nonzero: result is arg 1. FAddArg2Zero: StkP-1, IFUNext0; * Result already on stack *----------------------------------------------------------- FMul: MiscTable[22], * Floating multiply * a, b: REAL; * b ← PopLong[]; a ← PopLong[]; PushLong[a*b]; * Timing: 92 cycles, +6 if need to round. ~ 5.9 microseconds. *----------------------------------------------------------- RBase← RBase[FTemp0], StkP-2, SCall[FUnPack2]; T← ExpSign2, Branch[MulArgZero]; * +1: at least one arg is zero * XOR signs and add exponents. Subtract 200 from exponent to correct for doubling bias, * and add 1 to correct for 1-bit right shift of binary point during multiply * (binary point of product is between bits 1 and 2 rather than between 0 and 1). T← (ExpSign2)-(LShift[200, 7]C); * Subtract 200 from ExpSign2[0:8] T← T+(LShift[1, 7]C); * And add 1 (can't combine the constants, alas) ExpSign1← (ExpSign1)+T; * Now do the multiplications. Initial registers: * Frac1H = F1H (high 16 bits of arg 1) * Frac1L = F1L,,0 (low 8 bits of arg 1) * Frac2H = F2H (high 16 bits of arg 2) * Frac2L = F2L,,0 (low 8 bits of arg 2) * Intermediate register usage: * Frac1L and FTemp0 accumulate sticky bits * FTemp2 is the initial product register for the Multiply subroutines. * Do 8-step multiply of F1L*F2L, with initial product of zero. Frac1L← T← RSH[Frac1L, 10]; * Frac1L← 0,,F1L Frac2L← RSH[Frac2L, 10], * Frac2L← 0,,F2L Call[MultTx2L8I]; * Force 8 iterations, initial product 0 * Low product is FTemp2[8:15],,Q[0:7]. FTemp2[0:7] = Q[8:15] = 0. * Do 8-step multiply of F2H*F1L, using high 8 bits of previous result as initial product. FTemp0← Q; * Save low 8 bits for later use as sticky bits T← Frac2H, Cnt← 6S, Call[MultTx1L]; * Cross product is FTemp2[0:15]..Q[0:7]. Q[8:15] = 0. * Do 8-step multiply of F1H*F2L, with initial product of zero. Frac1L← Q; * Frac1L← low 8 bits of cross product T← Frac1H, ShC← T, * ShC← high 16 bits of cross product Call[MultTx2L8I]; * Force 8 iterations, initial product 0 * Cross product is FTemp2[0:15]..Q[0:7]. Q[8:15] = 0. * Add cross products, propagate carries, and merge sticky bits. T← (Frac1L)+Q; * Add low 8 bits of cross products Frac1L← (FTemp0) OR T; * Merge with sticky bits from low product T← ShC, Branch[.+2, ALU=0]; * Collapse to single sticky bit in Frac1L[15] Frac1L← 1C; FTemp2← (FTemp2)+T, XorSavedCarry; * Add high 16 bits of cross products * Do 16-step multiply of F1H*F2H, using high 16 bits of previous result as initial product. * Frac1H← (-1)+(carry out of sum of low and cross products). T← B← Frac1H, Cnt← 16S; Frac1H← T-T-1, XorSavedCarry, Call[MultTx2H]; * Final result is T,,Q. Merge in the sticky bit from low-order products and exit. Frac1L← (Frac1L) OR Q, DispTable[1, 2, 2]; T← (Frac1H)+T+1, Branch[Normalize], DispTable[1, 2, 2]; * One or both of the arguments is zero. Return zero with appropriate sign. T = ExpSign2 MulArgZero: ExpSign1← (ExpSign1) XOR T, Branch[FRePackZero]; *----------------------------------------------------------- * Unsigned multiply subroutines * Entry conditions (except as noted): * Cnt = n-2, where n is the number of iterations * T = multiplicand * FracXX = multiplier (register depends on entry point); * leftmost (16D-n) bits must be zero. * FTemp2 = initial product (to be added to low 16 bits of final product) * Exit conditions: * Product right-justified in T[0:15],,Q[0:n-1] * Q[n:15] = 0 * FTemp2 = copy of T * Carry = 1 iff T[0] = 1 * If n = 16D, caller must squash Multiply dispatches in the 2 instructions * following the Call. * Timing: n+2 *----------------------------------------------------------- Subroutine; * Entry point for multiplier = Frac1L MultTx1L: Q← Frac1L, DblBranch[MultiplierO, MultiplierE, R odd]; * Entry point for multiplier = Frac2L. * This entry forces 8 iterations with an initial product of zero. MultTx2L8I: FTemp2← A0, Cnt← 6S; Q← Frac2L, DblBranch[MultiplierO, MultiplierE, R odd]; * Entry point for multiplier = Frac2H MultTx2H: Q← Frac2H, DblBranch[MultiplierO, MultiplierE, R odd]; * Execute first Multiply purely for its side-effects (dispatch and shift Q) MultiplierE: PD← A0, Multiply, Branch[FM0]; MultiplierO: PD← A0, Multiply, Branch[FM1]; DispTable[4]; * here after Q[14] was 0 (no add) and continue FM0: FTemp2← A← FTemp2, Multiply, DblBranch[FM0E, FM0, Cnt=0&-1]; * here after Q[14] was 0 (no add) and exit FM0E: FTemp2← T← A← FTemp2, Multiply, Return; * here after Q[14] was 1 (add) and continue FM1: FTemp2← (FTemp2)+T, Multiply, DblBranch[FM0E, FM0, Cnt=0&-1]; * here after Q[14] was 1 (add) and exit FTemp2← T← (FTemp2)+T, Multiply, Return; TopLevel; *----------------------------------------------------------- FDiv: MiscTable[23], * Floating divide * a, b: REAL; * b ← PopLong[]; a ← PopLong[]; PushLong[a/b]; * Timing: 147 cycles, +2 if normalize, +5 if round. ~ 9.4 microseconds. *----------------------------------------------------------- RBase← RBase[FTemp0], StkP-2, SCall[FUnPack2]; T← ExpSign2, Branch[DivArgZero]; * +1: at least one arg is zero * XOR signs and subtract exponents. * Add 200 to resulting exponent to correct for cancellation of bias. T← (ExpSign2)-(LShift[200, 7]C); * Subtract 200 from ExpSign2[0:8] ExpSign1← (ExpSign1)-T; * First, transfer dividend to Frac2H ,, Frac2L and divisor to T ,, Q, * and unnormalize both of them by one bit so that significant dividend bits * aren't lost during the division. Frac1H← (Frac1H) RSH 1, Branch[.+2, R odd]; T← (Frac1L) RSH 1, Branch[.+2]; T← ((Frac1L)+1) RCY 1; * Know Frac1L is even Frac2L← T, Q← Frac2L; T← A← Frac2H, Multiply; * T,,Q ← (Frac2H ,, Frac2L) RSH 1 * Know Q[14]=0, so can't dispatch * Now do the division. * Must do total of 26 iterations: 24 for quotient bits, +1 more significant * bit in case we need to normalize, +1 bit for rounding. Frac2H← Frac1H, Call[DivFrac]; * Do 16 iterations Subroutine; Frac1H← Frac1L, CoReturn; * Preserve high quotient; do 10 more iterations * We may have subtracted too much (or not added enough) in the last iteration. * If so, adjust the remainder by adding back the divisor. Since the remainder * got shifted left one bit, we must double the divisor first. T← A← T, Divide, Frac1L, Branch[NoRemAdjust, R odd]; * T,,Q ← (T,,Q) LSH 1 Frac2L← (Frac2L)+Q; Frac2H← T← (Frac2H)+T, XorSavedCarry, Branch[.+2]; * Left-justify low quotient bits and zero sticky bit. * Then, if the remainder is nonzero, set the sticky bit. * Then normalize if necessary. We should have to left-shift at most once, * since the original operands were normalized. NoRemAdjust: T← Frac2H; PD← (Frac2L) OR T; Frac1L← LSH[Frac1L, 6], Branch[.+2, ALU=0]; Frac1L← (Frac1L)+1; * Set sticky bit T← Frac1H, Branch[Normalize]; * One or both of the arguments is zero. * Trap if divisor is zero; return zero with appropriate sign otherwise. DivArgZero: Frac2H, Branch[MulArgZero, R<0]; Branch[FloatTrap]; * Division by zero *----------------------------------------------------------- DivFrac: * Divide fractions * Enter: Frac2H ,, Frac2L = dividend (high-order bit must be zero) * T ,, Q = divisor (high-order bit must be zero) * Exit: Frac2H ,, Frac2L = remainder, left-justified * Frac1L = quotient bits (see below) * T and Q unchanged * When first called, executes 16 iterations and returns 16 high-order quotient bits. * When resumed with CoReturn, executes 10 more iterations and returns 10 low-order * quotient bits right-justified (other bits garbage). * Timing: first call: 66; resumption: 41 *----------------------------------------------------------- Subroutine; Cnt← 17S; * Previous quotient bit was a 1, i.e., dividend was >= divisor. * Subtract divisor from dividend and left shift dividend. DivSubStep: Frac2L← ((Frac2L)-Q) LSH 1; DivSubStep1: Frac2H← (Frac2H)-T-1, XorSavedCarry, DblBranch[DivSh1, DivSh0, ALU<0]; * Previous quotient bit was a 0, i.e., dividend was < divisor (subtracted * too much). Add divisor to dividend and left shift dividend. DivAddStep: Frac2L← ((Frac2L)+Q) LSH 1; DivAddStep1: Frac2H← (Frac2H)+T, XorSavedCarry, DblBranch[DivSh1, DivSh0, ALU<0]; * Shifted a zero out of low dividend (ALU<0 tested unshifted result). DivSh0: Frac2H← (Frac2H)+(Frac2H), DblBranch[DivQuot1, DivQuot0, Carry]; * Shifted a one out of low dividend (ALU<0 tested unshifted result). DivSh1: Frac2H← (Frac2H)+(Frac2H)+1, DblBranch[DivQuot1, DivQuot0, Carry]; * If the operation generated no carry then we have subtracted too much. * Shift a zero into the quotient and add the divisor next iteration. DivQuot0: Frac1L← (Frac1L)+(Frac1L), * Shift zero into quotient Branch[DivAddStep, Cnt#0&-1]; Cnt← 11S, CoReturn; Frac2L← ((Frac2L)+Q) LSH 1, Branch[DivAddStep1]; * If the operation generated a carry then we have not subtracted too much. * Shift a one into the quotient and subtract the divisor next iteration. DivQuot1: Frac1L← (Frac1L)+(Frac1L)+1, * Shift one into quotient Branch[DivSubStep, Cnt#0&-1]; Cnt← 11S, CoReturn; Frac2L← ((Frac2L)-Q) LSH 1, Branch[DivSubStep1]; TopLevel; *----------------------------------------------------------- FComp: MiscTable[24], * Floating compare * a, b: REAL; b ← PopLong[]; a ← PopLong[]; * Push[SELECT TRUE FROM a<b => -1, a=b => 0, a>b => 1, ENDCASE]; * Timing: 23 cycles usually, 24 if high parts equal. * ~ 1.5 microseconds *----------------------------------------------------------- RBase← RBase[FTemp0], StkP-2, SCall[FUnPack2]; T← Stack&+2, Branch[.+2]; * +1: at least one arg is zero * First compare the signs T← Stack&+2; * T← high arg1 PD← T XOR (Q← Stack&-1); * Q← high arg2 T← Stack&-1, FreezeBC, Branch[FCompSignsDiff, ALU<0]; * T← low arg2 * Signs equal, compare magnitudes. Q = high arg2, T = low arg2, StkP -> high arg1 PD← (Stack&-1)-Q, Branch[.+2, ALU#0]; * Compute high (arg1 - arg2) PD← (Stack)-T; * High parts equal, compute low (arg1 - arg2) * Carry = 1 if arg1 >= arg2 when treated as unsigned numbers. * The sense of this is inverted if the arguments are in fact negative, since * the representation is sign-magnitude rather than twos-complement. FCompTest: ExpSign1← (ExpSign1)+1, XorSavedCarry, Branch[FCompE, ALU=0]; ExpSign1, DblBranch[FCompL, FCompG, R odd]; * Signs unequal. Unless both arguments are zero, return "less" if arg1 is negative, * else "greater". Q = high arg2. FCompSignsDiff: PD← T-T, StkP-1, Q LSH 1; * Carry← 1 PD← (Frac1H) OR Q, Branch[FCompTest]; * ALU=0 iff both args are zero FCompL: StackT← -1C, IFUNext2; * arg1 < arg2 FCompE: StackT← A0, IFUNext2; * arg1 = arg2 FCompG: StackT← 1C, IFUNext2; * arg1 > arg2 *----------------------------------------------------------- Float: MiscTable[26], * Float a LONG INTEGER * a: LONG INTEGER ← PopLong[]; PushLong[REAL[a]]; * Timing: 20 cycles, +3 if arg < 2↑16, + 2*(15 - result exponent mod 16). * Average (8 normalizations required): 35 cycles or 2.3 microseconds *----------------------------------------------------------- PD← T, RBase← RBase[FTemp0], StkP-2; ExpSign1← Add[LShift[237, 7], 177]C, * Long integer = fraction * 2↑31 Branch[FloatNegative, ALU<0]; * Init sign to 1, branch if number negative Frac1L← Stack&+1; * Positive, fraction ← integer ExpSign1← (ExpSign1)-1, Branch[Normalize]; * Fix sign * T = high fraction, ALU>=0 for Normalize FloatNegative: T← A0, Q← Stack&+1; * Negative, fraction ← negative of integer Frac1L← T-Q; T← T-(Stack)-1, XorSavedCarry, Branch[Normalize]; *----------------------------------------------------------- Round: MiscTable[33], * Round to LONG INTEGER * a: REAL ← PopLong[]; PushLong[RoundToLongInteger[a]]; * Timing: 23 cycles if result is zero, * 29 if 0 < |result| < 2↑15 * 32 if 2↑15 <= |result| < 2↑31 *----------------------------------------------------------- T← Add[LShift[25, 2], 1]C, Branch[FixReDispatch]; *----------------------------------------------------------- Fix: MiscTable[25], * Fix to LONG INTEGER * a: REAL ← PopLong[]; PushLong[FixToLongInteger[a]]; * Timing: 17 cycles if result is zero, * 20 if 0 < |result| < 2↑15 * 23 if 2↑15 <= |result| < 2↑31 *----------------------------------------------------------- RBase← RBase[FTemp0], StkP-2, Call[FixLong]; * (Q&FTemp1),,T ← result T← T-1, ExpSign1, Branch[.+3, R odd]; * Push positive result Stack&+1← T+1; StackT← Q, IFUNext2; * Push negative result Stack&+1← NOT T, Branch[.+2, Carry']; StackT← (0S)-Q-1, IFUNext2; StackT← (0S)-Q, IFUNext2; *----------------------------------------------------------- RoundI: MiscTable[34], * Round to INTEGER * a: REAL ← PopLong[]; Push[INTEGER[RoundToLongInteger[a]]]; * Timing: 20 cycles if result is zero, * 26 if 0 < |result| < 2↑15 *----------------------------------------------------------- T← Add[LShift[27, 2], 1]C, Branch[FixReDispatch]; *----------------------------------------------------------- FixI: MiscTable[27], * Fix to INTEGER * a: REAL ← PopLong[]; Push[INTEGER[FixToLongInteger[a]]]; * Timing: 17 cycles if result is zero, * 20 if 0 < |result| < 2↑15 *----------------------------------------------------------- RBase← RBase[FTemp0], StkP-2, Call[FixLong]; * (Q&FTemp1),,T ← result PD← RCY[FTemp1, T, 17]; * See if result < 2↑15 FTemp1← (FTemp1) OR T, Branch[FixIOverflow, ALU#0]; * Result < 2↑15, push result with correct sign. ExpSign1, Branch[.+2, R odd]; * Test sign StackT← T, IFUNext2; * Push positive result StackT← (0S)-T, IFUNext2; * Push negative result * Result >= 2↑15. If it is exactly 2↑15 and negative then push -2↑15; * otherwise trap. FTemp1=100000 iff magnitude=2↑15. FixIOverflow: T← LSH[ExpSign1, 17]; * 100000 if negative, 0 if positive PD← (FTemp1)#T, Branch[FixTrapALU#0]; * Know FTemp1#0; ALU=0 iff both are 100000 *----------------------------------------------------------- RoundC: MiscTable[35], * Round to CARDINAL * a: REAL ← PopLong[]; Push[CARDINAL[RoundToLongInteger[a]]]; * Timing: 20 cycles if result is zero, * 25 if 0 < result < 2↑15 * 29 if 2↑15 <= result < 2↑16 *----------------------------------------------------------- T← Add[LShift[30, 2], 1]C, Branch[FixReDispatch]; *----------------------------------------------------------- FixC: MiscTable[30], * Fix to CARDINAL * a: REAL ← PopLong[]; Push[CARDINAL[FixToLongInteger[a]]]; * Timing: 17 cycles if result is zero, * 19 if 0 < result < 2↑15 * 22 if 2↑15 <= result < 2↑16 *----------------------------------------------------------- RBase← RBase[FTemp0], StkP-2, Call[FixLong]; * (Q&FTemp1),,T ← result PD← Q, ExpSign1, Branch[.+2, R even]; * Result in [0..2↑16)? Branch[FloatTrap]; * Negative * Ok if high part 0, else trap * Push result from T if ALU=0; trap if ALU#0. FixTrapALU#0: Branch[.+2, ALU=0]; Branch[FloatTrap]; StackT← T, IFUNext2; *----------------------------------------------------------- FixReDispatch: * Re-dispatch Round opcode to the equivalent Fix opcode. * Enter: T = MT0Loc offset for desired Fix opcode (4*alpha +1). * Exit: Branches to specified place, with BDispatch← 2 pending. * This causes the Call[FixLong] to be converted into Call[RoundLong]. *----------------------------------------------------------- T← T+(BigBDispatch← T), StkP-1; * T← xxx2 T← Stack&+1, BDispatch← T, BranchExternal[MT0Loc]; *----------------------------------------------------------- FScale: MiscTable[37], * Floating Scale * scale: INTEGER ← Pop[]; a: REAL ← PopLong; PushLong[a * (2.0**scale)]; * Timing: 14 cycles if floating point argument is nonzero, 10 if zero. *----------------------------------------------------------- * Call FUnPack1 solely to filter out denormalized numbers and NaNs. StkP-2; * Leave FF free for placement T← Stack&-1, RBase← RBase[FTemp0], SCall[FUnpack1]; IFUNext0; * Scaling zero leaves number unchanged * Packed exponent is excess-127, and legal values are IN [1..376B]. T← LDF[Stack&+1, 10, 7]; * Extract exponent from packed number T← T+(Stack); * Exponent + scale PD← T-(377C), Branch[FScUnderflow, ALU=0]; * Result must be IN [1..376B] T← LSH[Stack&-1, 7], Branch[FScOverflow, Carry]; StackT← (StackT)+T, IFUNext2; * Ok, just add scale to packed result FScUnderflow: Branch[FloatTrap]; FScOverflow: Branch[FloatTrap]; *----------------------------------------------------------- FixLong: * Subroutine to fix to a LONG INTEGER. * Enter: one floating point number on stack * Exit: magnitude of LONG INTEGER (always positive) in Q,,T * FTemp1 = a copy of Q (high result) * unpacked floating point number in ExpSign1, Frac1H, Frac1L * StkP addresses low word for result (i.e., =1 if minimal stack) * Does not return but rather traps for infinity, denormalized, NaN, * or number too large for LONG INTEGER. * Caller may resume FixLong to perform rounding, by saving T in FTemp2 * and executing a Return. * Clobbers FTemp1, ShC * Timing: 13 cycles if result is zero * 15 if 0 < |result| < 2↑15 * 18 if 2↑15 <= |result| < 2↑31 *----------------------------------------------------------- * Note that FUnpack1 never skips, because .+1 is forced to be odd. FTemp1← Link, Call[FUnPack1], DispTable[3, 17, 0], Global; * At[xxx0] FTemp1← A0, Link← FTemp1, Branch[FixTestExp]; * At[xxx1] *----------------------------------------------------------- RoundLong: * Subroutine to round to a LONG INTEGER. * Never called directly, but only as an "xor 2" pair with FixLong. * Uses FixLong internally; all comments for FixLong apply here, except: * Clobbers FTemp2. * Timing: 16 cycles if result is zero * 21 if 0 < |result| < 2↑15 * 25 if 2↑15 <= |result| < 2↑31 * + [1..3] cycles if have to round up *----------------------------------------------------------- FTemp2← Link, Call[FixLong]; * At[xxx2] Fix and prepare to round Subroutine; * Following instruction restores RoundLong's return link and jumps back * into FixLong at the appropriate place. Note Link← overrides Return's * normal action of loading Link with .+1. FTemp2← T, Link← FTemp2, Return; * Save low word and complete rounding * Continuation of FixLong: FixTestExp: T← (ExpSign1)+(ExpSign1); * Move exponent to T[0:7] T← T-(LShift[177, 10]C); * T[0:7]← unbiased exponent +1 T← T-(LShift[20, 10]C), StkP-1, Branch[FixZero, ALU<0]; T← T-(LShift[20, 10]C), Branch[FixExpLs17, ALU<0]; T← T-(LShift[20, 10]C), Branch[FixExpLs37, ALU<0]; Branch[FloatTrap]; * Exponent > 36, overflow * FixLong/RoundLong (cont'd) * Unbiased exponent less than -1 (i.e., arg1 < 0.5). Just return zero. FixZero: T← Q← FTemp1, CoReturn; FixRoundRet: Q← FTemp1, Return; * If asked to round, do nothing; Q← 0 * Unbiased exponent is in [-1..16B]. T[0:7] now has exponent-37B, i.e., * in [177740..177757], which when properly positioned gives SHA=T, SHB=R. * Shift control is LCY[T, R, exponent+1] = RCY[R, T, 17B-exponent]. FixExpLs17: T← Frac1H, ShC← T; T← ShiftNoMask[FTemp1], Q← FTemp1, * T← LCY[Frac1H, 0, [0..17]], Q← 0 CoReturn; * Resume here to round. Rounding bits are in both Frac1H and Frac1L. T← Frac1L; T← ShiftNoMask[Frac1H], Branch[FixRoundTest, ALU=0]; T← T OR (1C), Branch[FixRoundTest]; * Sticky bit for discarded result * Unbiased exponent is in [17B..36B]. T[0:7] now has exponent-57B, i.e., * in [177740..177757], which when properly positioned gives SHA=T, SHB=R. * Shift control is LCY[T, R, exponent-17B] = RCY[R, T, 37B-exponent]. FixExpLs37: T← Frac1H, ShC← T; T← FTemp1← ShiftNoMask[FTemp1]; * T← LCY[Frac1H, 0, [0..17]] T← Frac1L, Q← T; T← ShiftNoMask[Frac1H], CoReturn; * T← LCY[Frac1L, Frac1H, [0..17]] * Resume here to round. Rounding bits are only in Frac1L. T← A0; T← ShiftNoMask[Frac1L]; * Now have rounding bit in T[0] and sticky bits in T[1:15]. ALU = T. FixRoundTest: PD← T-1, Branch[.+2, ALU<0]; * Rounding possible? T← FTemp2, Return; * Not possible, restore T and return * If T>100000 then round up always (ALU<0). * If T=100000 then round up iff lowest significant bit is a one (R odd). T← (FTemp2)+1, Branch[.+2, ALU<0, R odd]; T← FTemp2, Return; * Don't round, just restore T FTemp1← A← FTemp1, XorSavedCarry, Branch[FixRoundRet]; * Round up *----------------------------------------------------------- FUnPack2: * Pop and unpack two floating-point arguments. * Enter: T = top-of-stack, StkP points to TOS-1 * Exit: ExpSign2, Frac2H, Frac2L set up with argument 2 (right); ExpSign2[13:14]=00 * ExpSign1, Frac1H, Frac1L set up with argument 1 (left); ExpSign1[13:14]=10 * StkP addresses high word of arg 1 (i.e., =2 if minimal stack) * Call by: SCall[FUnPack2] * Returns +1: at least one argument is zero * +2: both arguments are nonzero * Returns only for normal numbers or true zero. * Traps if denormalized, infinity, or Not-a-Number. * Clobbers Q * Timing: 15 cycles normally, 16 if arg 2 is zero. *----------------------------------------------------------- Subroutine; ExpSign2← T AND (177600C), Global; T← RCY[T, Stack, 10]; * Garbage bit and top 15 fraction bits ExpSign2← (ExpSign2) AND (77777C), * Exponent in bits 1:8, all else zero Branch[.+2, R<0]; * Branch if negative ExpSign2← (ExpSign2)+(200C), * Positive, add 1 to exponent, B15 ← 0 DblBranch[Exp2Zero, .+2, ALU=0]; * Branch if exponent zero ExpSign2← (ExpSign2)+(201C), * Negative, add 1 to exponent, B15 ← 1 Branch[Exp2Zero, ALU=0]; * Branch if exponent zero Frac2H← T OR (100000C), * Prefix explicit "1." to fraction Branch[Exp2NaN, ALU<0]; * Branch if exponent was 377 T← LSH[Stack&-1, 10]; * Left-justify low 8 fraction bits Frac2L← T; T← Stack&-1; * Now do arg 1 ExpSign1← T AND (177600C), Branch[FUnPack1a]; Exp2Zero: Frac2H← (Stack&-1) OR T; * See if entire fraction is zero Frac2L← A0, Branch[Arg2DeNorm, ALU#0]; * Branch if not true zero TopLevel; T← Stack&-1, Q← Link, SCall[FUnPack1]; * Zero, unpack other arg Link← Q, Branch[.+2]; * Return +1 regardless of what FUnpack1 did Link← Q; Subroutine; ExpSign2← (ExpSign2) AND (1C), Return; TopLevel; Arg2DeNorm: Branch[FloatTrap]; * Denormalized number Exp2NaN: Branch[FloatTrap]; * Not-a-Number *----------------------------------------------------------- FUnPack1: * Pop and unpack one floating-point argument. * Enter: T = top-of-stack, StkP points to TOS-1 * Exit: ExpSign1, Frac1H, Frac1L set up with argument * StkP addresses high word of arg 1 (i.e., =2 if minimal stack) * Call by: SCall[FUnPack1] * Returns +1: argument is zero * +2: argument is nonzero * Returns only for normal numbers or true zero. * Traps if denormalized, infinity, or Not-a-Number. * Timing: 7 cycles normally. *----------------------------------------------------------- Subroutine; ExpSign1← T AND (177600C), Global; FUnPack1a: T← RCY[T, Stack, 10]; * Garbage bit and top 15 fraction bits ExpSign1← (ExpSign1) AND (77777C), * Exponent in bits 1:8, all else zero Branch[.+2, R<0]; * Branch if negative ExpSign1← (ExpSign1)+(204C), * Positive, add 1 to exponent, [13:14]←10, [15]←0 DblBranch[Exp1Zero, .+2, ALU=0]; * Branch if exponent zero ExpSign1← (ExpSign1)+(205C), * Negative, add 1 to exponent, [13:14]←10, [15]←1 Branch[Exp1Zero, ALU=0]; * Branch if exponent zero Frac1H← T OR (100000C), * Prefix explicit "1" to fraction Branch[Exp1NaN, ALU<0]; * Branch if exponent was 377 T← LSH[Stack&+1, 10]; * Left-justify low 8 fraction bits Frac1L← T, Return[Carry']; * Always skip (carry is always zero here) Exp1Zero: Frac1H← (Stack&+1) OR T; * See if entire fraction is zero Frac1L← A0, Branch[Arg1DeNorm, ALU#0]; * Branch if not true zero ExpSign1← (ExpSign1) AND (1C), Return; * Zero, return +1 TopLevel; Arg1DeNorm: Branch[FloatTrap]; * Denormalized number Exp1NaN: Branch[FloatTrap]; * Not-a-Number *----------------------------------------------------------- Normalize: * Normalize and re-pack floating-point result. * Enter: ExpSign1, T, Frac1L contain unpacked result * T = ALU = high fraction. * StkP addresses high word of result (i.e., =2 if minimal stack) * Timing: for nonzero result: 11 cycles minimum, +3 if need to normalize at all, * +2*(n MOD 16) if n>1, where n is the number of normalization steps, * +3 if n>15, +5 if need to round, +2 if rounding causes a carry * out of Frac1L, +1 or 2 in extremely rare cases. * For zero result: 6 cycles *----------------------------------------------------------- * See if result is already normalized or entirely zero. * Note that we want the cases of no normalization, one-step normalization, * and result entirely zero to be the fastest, since they are by far the most common. * Therefore, do the first left shift in-line while branching on the other conditions. PD← T OR (Q← Frac1L), * ALU← 0 iff entire fraction is 0 Branch[NormAlready, ALU<0]; * Branch if already normalized Frac1H← A← T, Divide, * (Frac1H,,Q) ← (T,,Q) LSH 1 Branch[NormalizeZero, ALU=0]; * Branch if fraction is zero ExpSign1← (ExpSign1)-(LShift[1, 7]C), * Subtract one from exponent Branch[NormBegin, ALU#0]; * Branch if high fraction was nonzero * If the high word of the fraction was zero, we discover that after having left-shifted * the fraction once. Effectively, left-shift the fraction 16 bits and subtract * 16D from the exponent. Actually, undo the first left shift and subtract only 15D * from the exponent, in case the first left shift moved a one into the high fraction. ExpSign1← (ExpSign1)+(LShift[1, 7]C); * Can't encode the constant I really want! ExpSign1← (ExpSign1)-(LShift[20, 7]C); Frac1H← Frac1L; * Left-shift original fraction 16 bits Q← T, Branch[NormLoop]; * Q← 0 * In this loop, the exponent is in ExpSign1[0:8] and the fraction in Frac1H ,, Q. * Left shift the fraction and decrement the exponent until the high-order bit * of the fraction is a one. NormBegin: T← A0, Frac1H, Branch[NormDone1, R<0]; * Branch if one shift was enough NormLoop: Frac1H← A← Frac1H, Divide, Branch[NormDone, R<0]; * (Frac1H,,Q) ← (Frac1H,,Q) LSH 1 ExpSign1← (ExpSign1)-(LShift[1, 7]C), Branch[NormLoop]; * When we bail out of the loop, the exponent is correct, but we have left-shifted * the fraction one too many times. Right-shift the fraction and exit. NormDone: Frac1H← (Frac1H)-T, Multiply; * (Frac1H,,Q) ← 1,,((Frac1H,,Q) RSH 1) NormDone1: Frac1L← Q, Branch[FRePackNonzero]; * Multiply dispatch pending!! NormAlready: Frac1H← T, Branch[FRePackNonzero]; * Placement (sigh) * Result was exactly zero: push +0 as answer. NormalizeZero: ExpSign1← A0, Branch[FRePackZero]; *----------------------------------------------------------- FRePackNonzero: * Re-pack nonzero floating-point result. * Enter: ExpSign1, Frac1H, Frac1L contain unpacked result, which must be normalized but * need not have its leading "1" so long as rounding can't carry into this bit. * StkP addresses high word of result (i.e., =2 if minimal stack) * Timing: 9 cycles minimum, +5 if need to round, +2 if rounding causes a carry * out of Frac1L, +1 or 2 in extremely rare cases. *----------------------------------------------------------- * Prepare to round according to Round-to-Nearest convention. Frac1L[8:15] are fraction * bits that will be rounded off; result is exact only if these bits are zero. PD← (Frac1L) AND (377C), DispTable[1, 2, 2]; FRePackNZ1: ExpSign1← (ExpSign1) OR (176C), * Put ones in all unused bits of ExpSign1 Branch[NoRounding, ALU=0]; * Inexact result. Round up if result is greater than halfway between representable * numbers, down if less than halfway. If exactly halfway, round in direction that makes * least significant bit of result zero. Adding 1 at the Frac1L[8] position causes * a carry into bit 7 iff the result is >= halfway between representable numbers. PD← (Frac1L) AND (177C); Frac1L← (Frac1L)+(200C), Branch[.+2, ALU#0]; * Exactly halfway. But we have already rounded up. * If the least significant bit was 1, it is now 0 (correct). * If it was 0, it is now 1 (incorrect). But in the latter case, no carries * have propagated beyond the least significant bit, so... Frac1L← (Frac1L) AND NOT (400C); * Just zero the bit to fix it * Now set the sticky flag and trap if appropriate. * Note we have not propagated the carry out of the low word yet, so we must * perform only logical ALU operations that don't clobber the carry flag. T← B← Frac1H, RBase← RBase[Sticky]; Sticky← (Sticky) OR (1C), Branch[InexactTrap, R<0]; T← T+1, RBase← RBase[FTemp0], * Prepare to do carry if appropriate Branch[DoneRounding, Carry']; * There was a carry out of Frac1L. Propagate it to Frac1H. * If this causes a carry out of Frac1H, the rounded fraction is exactly 2.0, which * we must normalize to 1.0; i.e., set fraction to 1.0 and increment exponent. Frac1H← T, Branch[.+2, Carry']; ExpSign1← (ExpSign1)+(LShift[1, 7]C); ExpSign1← (ExpSign1)-(LShift[2, 7]C), DblBranch[ExpOverflow, .+3, R<0]; * Done rounding. Check for exponent over/underflow, and repack and push result. DoneRounding: ExpSign1← (ExpSign1)-(LShift[2, 7]C), DblBranch[ExpOverflow, .+2, R<0]; NoRounding: ExpSign1← (ExpSign1)-(LShift[2, 7]C), * Subtract 2 from exponent Branch[ExpOverflow, R<0]; * Branch if exponent > 377B originally T← LDF[Frac1H, 7, 10], * Extract high 7 fraction bits, exclude leading 1 Branch[ExpUnderflow, ALU<0]; * Branch if exponent < 2 originally * At this point, ExpSign1[1:8] = desired exponent -1, and [9:15] = 176 if the * sign is positive, 177 if negative. Thus adding 2 (if positive) or 1 (negative) * will correctly adjust the exponent and clear out [9:15]. T← (ExpSign1)+T+1, * Merge exponent with fraction and add 1 Branch[.+2, R odd]; * Branch if negative Stack&-1← T+1, Branch[.+2]; * Positive, add 1 more to finish fixing exponent Stack&-1← T OR (100000C); * Negative, set sign bit of result T← Frac1H; * Construct low fraction T← RCY[T, Frac1L, 10]; Stack&+1← T, IFUNext0; InexactTrap: Branch[FloatTrap]; ExpUnderflow: Branch[FloatTrap]; ExpOverflow: Branch[FloatTrap]; *----------------------------------------------------------- FRePackZero: * Push a result of zero with the correct sign * Enter: ExpSign1 has correct sign * StkP addresses high word of result (i.e., =2 if minimal stack) * Timing: 3 cycles *----------------------------------------------------------- T← LSH[ExpSign1, 17]; * Slide sign to bit 0 Stack&-1← T; * Push true zero with correct sign FRePackZ2: Stack&+1← A0, IFUNext0; *----------------------------------------------------------- FloatTrap: * Trap to the software floating-point handler. * Alto mode: * Enter: OTPReg = 4*alpha or 4*alpha+1 (left over from MISC dispatch); * odd iff entry point 2 was taken * Restores StkP, puts the alpha byte in OTPReg, and traps to SD[137]. * PrincOps mode: * Invokes the Cedar OpcodeTrap mechanism *----------------------------------------------------------- TopLevel; DontKnowRBase; RBase← RBase[RTemp0]; :If[AltoMode]; ********** Alto version ********** RestoreStkP; :IfMEP; OTPReg← LDF[OTPReg, 10, 2], Branch[.+2, R even]; StkP+1; * Entry 2, adjust saved StkP :Else; OTPReg← LDF[OTPReg, 10, 2]; :EndIf; T← 137C, Branch[SavePCAndTrap]; :Else; ******** PrincOps version ******** Branch[MiscOpcodeTrap]; :EndIf; **********************************