{File name: NewLispFPTChip.mc Last edited by cal 19-Oct-84 9:14:42 Last edited by Sturgis 15-Sep-83 16:40:30 Descrition: Floating point code for Lisp {modified from Cedar fpt code} Created by H. Sturgis } {******************************************************************** All LISP Floating Point Opcodes have two arguments, so all the opcodes will flow through common code which will verify the two arguments are Floating Point numbers, and set up for the actual execution. } { save TOS and TOSH before ReMap, set L1 ← L1.fixFV, set L3 ← L3.FloatArg2 verify FloatpType fetch and unpack to Arg2 U registers {may page fault} set L3 ← L3.FloatArg1 read [S] and [S - 1] verify FloatpType fetch and unpack to Arg1 U registers {may page fault} {Opcode dependent execution} {goto ufnZ if want to trap} pack result, box result return } { put the 32 bits into some fixed place find type and verify that it is a Fpt mapping the Fpt may fault -- be prepared! get the 32 bit value to a fixed place return } { following is in bank 1 @FPLUS2: opcode[350'b], Bank ← FPTBank, L2 ← L2.Fplus, c1; uTOS ← TOS, L3 ← L3.FunSecond, c2; uTOSH ← TOSH, CROSS[FPTCode], c3; @FDIFFERENCE: opcode[351'b], Bank ← FPTBank, L2 ← L2.Fdiff, c1; uTOS ← TOS, L3 ← L3.FunSecond, c2; uTOSH ← TOSH, CROSS[FPTCode], c3; @FTIMES2: opcode[352'b], Bank ← FPTBank, L2 ← L2.Ftimes, c1; uTOS ← TOS, L3 ← L3.FunSecond, c2; uTOSH ← TOSH, CROSS[FPTCode], c3; @FQUOTIENT: opcode[353'b], Bank ← FPTBank, L2 ← L2.Fquot, c1; uTOS ← TOS, L3 ← L3.FunUSecond, c2; uTOSH ← TOSH, CROSS[FPTCode], c3; @FGREATERP: opcode[362'b], Bank ← FPTBank, L2 ← L2.Fgreat, c1; uTOS ← TOS, L3 ← L3.FunSecond, c2; uTOSH ← TOSH, CROSS[FPTCode], c3; preceding is in bank 1 } at[FPTCode], L1 ← L1.RestoreTosB2, c1; FloatNop, CALL[FloatIt], c2; at[L3.FunSecond, 10, FloatItRet], MAR ← [rhS, S - 1], c1; uArg2Hi ← TOSH, CANCELBR[$, 2], c2; TOSH ← MD, FloatNop, c3; MAR ← [rhS, S + 0], c1; uArg2Lo ← TOS, CANCELBR[$, 2], c2; TOS ← MD, FloatNop, c3; L3 ← L3.FunFirst, c1; FloatNop, CALL[FloatIt], c2; at[L3.FunFirst, 10, FloatItRet], Rx ← 0FF + 1, L0 ← L0.Boxed, c1;{set PPort to read} fptprep: Q ← uPPsave, c2; PPort ← Q and ~Rx, c3; FloatNop, c1; FloatNop, c2; Q ← uFLmode, c3; AltUaddr, Ybus ← Q, L2Disp, c1; FloatMode, FloatFLOW, DISP4[FLop], c2; at[L2.Fplus, 10, FLop], ufloatplus ← TOSH, c3; FloatAB ← uArg2Hi, c1; FloatAB ← uArg2Lo, c2; FloatA ← ufloatplus, FLPlus, GOTO[FLFastComm], c3; FLFastComm: FloatA ← TOS LRot0, c1; FloatStartFlow, c2; {wait}, c3; {wait}, c1; Rx ← uPPsave, {wait}, c2; FloatUnloadS, Float.M, c3; FloatUnloadS, Float.L, c1; FLUnloadHere: Q ← PPort, c2; TOSH ← uNewValHi ← FloatResult, c3; Ybus ← Q, YDisp, c1; TOS ← uNewValLo ← FloatResult, L0Disp, DISP4[FLres, 1], c2; {note that chip status bits are COMPLEMENTED} PPort ← Rx, DISP2[FLExit], c3, at[0F, 10, FLres];{no exceptions} PPort ← Rx, CANCELBR[FLinexact, 3], c3, at[0D, 10, FLres];{inexact} PPort ← Rx, CANCELBR[FLerror, 3], c3, at[0B, 10, FLres];{exponent underflow} PPort ← Rx, CANCELBR[FLerror, 3], c3, at[09, 10, FLres];{exponent underflow and inexact} PPort ← Rx, CANCELBR[FLerror, 3], c3, at[07, 10, FLres];{unused} PPort ← Rx, CANCELBR[FLerror, 3], c3, at[05, 10, FLres];{exponent overflow and inexact} PPort ← Rx, CANCELBR[FLerror, 3], c3, at[03, 10, FLres];{invalid operands} PPort ← Rx, CANCELBR[FLerror, 3], c3, at[01, 10, FLres];{denormalized operand} {box result -- 1 byte opcodes} at[L0.Boxed, 4, FLExit], Bank ← EmuBank, L1 ← L1.fixFV, c1; L3 ← L3.FptArg1, c2; Q ← LS4FptType, CROSS[CCEntry], c3; {leave result unboxed -- 2 byte opcodes} at[L0.UnBoxed, 4, FLExit], Xbus ← ib, c1; , c2; S ← S - 2, GOTO[c1.pc2B2], c3; c1.pc2B2: Bank ← EmuBank, c1; ib.pc2B2: PC ← PC + 1, IBDisp, L2 ← L2.0, c2; dni.nopB2: L2 ← L2.0, DISPNI[OpTableB2], c3; FLerror: {goto ufn} GOTO[ufnZ22], c1; FLinexact: {set inexact bit, goto ufn if desired} Rx ← 10, c1; Rx ← Rx or uFLmode, c2; , c3; Ybus ← Rx, NegBr, c1; uFLmode ← Rx, L0Disp, BRANCH[FLinexok, FLinexnok], c2; FLinexok: DISP2[FLExit], c3; FLinexnok: CANCELBR[FLerror, 3], c3; { ********** } at[L2.Fdiff, 10, FLop], ufloatdiff ← TOSH, c3; FloatAB ← uArg2Hi, c1; FloatAB ← uArg2Lo, c2; FloatA ← ufloatdiff, FLAMinusB, GOTO[FLFastComm], c3; { ********** } at[L2.Fidiff, 10, FLop], ufloatidiff ← TOSH, c3; FloatAB ← uArg2Hi, c1; FloatAB ← uArg2Lo, c2; FloatA ← ufloatidiff, FLBMinusA, GOTO[FLFastComm], c3; { ********** } at[L2.Ftimes, 10, FLop], ufloattimes ← TOSH, c3; FloatAB ← uArg2Hi, c1; FloatAB ← uArg2Lo, c2; FloatA ← ufloattimes, FLTimes.A.B, c3; FloatA ← TOS LRot0, c1; FloatStartFlow, c2; {wait}, c3; Rx ← uPPsave{wait}, c1; {wait}, c2; FloatUnloadP, Float.M, c3; FloatUnloadP, Float.L, GOTO[FLUnloadHere], c1; { ********* } { compare from FGREATERP, UB2Great, UB2Max, UB2Min L2 has op L0 has exit first arg in TOSH and TOS second arg in uArg2Hi and uArg2Lo } at[L2.Fgreat, 10, FLop], Q ← uArg2Hi, GOTO[fptcomp], c3; at[L2.Fmax, 10, FLop], Q ← uArg2Hi, GOTO[fptcomp], c3; at[L2.Fmin, 10, FLop], Q ← uArg2Hi, GOTO[fptcomp], c3; fptcomp: Ybus ← Q xor TOSH, NegBr, c1; Ybus ← Q, NegBr, BRANCH[fptCsame, fptCdiff], c2; fptCdiff: Ybus ← Q, NegBr, CANCELBR[$], c3; S ← S - 2, BRANCH[fptC2ge1, fptC1gt2], L2Disp, c1; fptCsame: Rx ← uArg2Lo, BRANCH[fptCpos, fptCneg], c3; fptCpos: Ybus ← Rx - TOS, CarryBr, c1; BRANCH[fptCcar, fptCnocar], c2; fptCcar: Ybus ← Q - TOSH - 1, NegBr, GOTO[fptCptest], c3; fptCptest: S ← S - 2, BRANCH[fptC2ge1, fptC1gt2], L2Disp, c1; fptCnocar: Ybus ← Q - TOSH, NegBr, GOTO[fptCptest], c3; fptCneg: Ybus ← TOS - Rx, CarryBr, c1; BRANCH[fptCncar, fptCnnocar], c2; fptCncar: Ybus ← TOSH - Q - 1, NegBr, GOTO[fptCptest], c3; fptCnnocar: Ybus ← TOSH - Q, NegBr, GOTO[fptCptest], c3; fptC1gt2: DISP4[fptCop1gt2], c2; fptC2ge1: DISP4[fptCop2ge1], c2; TOS ← KTval, GOTO[fptCex], L0Disp, c3, at[L2.Fgreat, 10, fptCop1gt2]; TOS ← 0, GOTO[fptCex], L0Disp, c3, at[L2.Fgreat, 10, fptCop2ge1]; Xbus ← ib, GOTO[c1.pc2B2], c3, at[L2.Fmax, 10, fptCop1gt2]; TOSH ← uArg2Hi, GOTO[fptCswap], c3, at[L2.Fmax, 10, fptCop2ge1]; TOSH ← uArg2Hi, GOTO[fptCswap], c3, at[L2.Fmin, 10, fptCop1gt2]; Xbus ← ib, GOTO[c1.pc2B2], c3, at[L2.Fmin, 10, fptCop2ge1]; fptCswap: TOS ← uArg2Lo, c1; Xbus ← ib, c2; GOTO[c1.pc2B2], c3; fptCex: TOSH ← 0, DISP4[fptCdone], c1; , c2, at[L0.Boxed, 10, fptCdone]; GOTO[c1.pc1B2], c3; c1.pc1B2: Bank ← EmuBank, c1; PC ← PC + PC16, IBDisp, L2 ← L2.0, c2; L2 ← L2.0, DISPNI[OpTableB2], c3; Xbus ← ib, c2, at[L0.UnBoxed, 10, fptCdone]; GOTO[c1.pc2B2], c3; { ********** } at[L3.FunUSecond, 10, FloatItRet], Rx ← TT LRot8 and Q, {exponent} c1; ub2Qcont2: TT ← TT and 1,{the sign bit} c2; uExp2 ← Rx, ZeroBr, c3; Ybus ← Rx xor Q, ZeroBr, BRANCH[$, UP2ZeroE1], c1; uSign2 ← TT, BRANCH[$, FprepufnA3], c2; TT ← TOSH or 200'b, {implicit leading 1 bit} GOTO[Unpack2A], c3; UP2ZeroE1: uSign2 ← TT, CANCELBR[$], c2; TT ← TOS and 177'b, {force leading bit to be 0} c3; Unpack2A: TOS ← TOS LRot8, c1; Q ← ~377'b, c2; uLowHalf2 ← TOS and Q, c3; TOS ← TOS and 377'b, c1; TT ← (TT LRot8 ) and Q, c2; Ybus ← Rx, ZeroBr, {test for zero exponent again} c3; uHighHalf2 ← TOS or TT, BRANCH[UP2A, $], c1; TOS ← TOS or TT, c2; TOS ← TOS or uLowHalf2, c3; Ybus ← TOS, NZeroBr, c1; UP2A: BRANCH[$, FprepufnB3], c2; , c3; MAR ← [rhS, S - 1], c1; Q ← 0FF, CANCELBR[$, 2], c2; TOSH ← MD, c3; MAR ← [rhS, S + 0], c1; TT ← TOSH LRot1, L3Disp, c2; TOS ← MD, DISP4[fptQ2ret], c3; at[L3.UB2Q2, 10, fptQ2ret], Rx ← TT LRot8 and Q, GOTO[ub2Qcont1], c1; at[L3.FunUSecond, 10, fptQ2ret], L3 ← L3.FunUFirst, c1; FloatNop, CALL[FloatIt], c2; at[L3.FunUFirst, 10, FloatItRet], Rx ← TT LRot8 and Q, {exponent} c1; ub2Qcont1: TT ← TT and 1,{the sign bit} c2; uExp1 ← Rx, ZeroBr, c3; Ybus ← Rx xor Q, ZeroBr, BRANCH[$, UP1ZeroE1], c1; uSign1 ← TT, BRANCH[$, FprepufnC3], c2; TT ← TOSH or 200'b, {implicit leading 1 bit} GOTO[Unpack1A], c3; UP1ZeroE1: uSign1 ← TT, CANCELBR[$], c2; TT ← TOSH and 177'b, {force leading bit to be 0} c3; Unpack1A: TOS ← TOS LRot8, c1; Q ← ~377'b, c2; uLowHalf1 ← TOS and Q, c3; TOS ← TOS and 377'b, c1; TT ← (TT LRot8 ) and Q, c2; Ybus ← Rx, ZeroBr, {test for zero exponent again} c3; uHighHalf1 ← TOS or TT, BRANCH[UP1A, $], c1; TOS ← TOS or TT, c2; TOS ← TOS or uLowHalf1, c3; Ybus ← TOS, NZeroBr, c1; UP1A: BRANCH[$, FprepufnD3], c2; L2Disp, c3; RET[FptPrepRet], c1; {**************************************************************************** uSign2: [0..0]=s1, [1..15]=0 uExp2: [0..7]=0, [8..15]=exp2 uHighHalf2: [0..0]=1, [1..7]=fract2a, [8..15]=fract2b (if exp2 = 0 then [0..0] = 0) uLowHalf2: [0..7]=fract2c, [8..15]=0 uSign1: [0..0]=s1, [1..15]=0 uExp1: [0..7]=0, [8..15]=exp1 uHighHalf1: [0..0]=1, [1..7]=fract1a, [8..15]=fract1b (if exp1 = 0 then [0..0] = 0) uLowHalf1: [0..7]=fract1c, [8..15]=0 On Exit: IF <x0, x1, ...> = <uHighHalf1, uLowHalf1> THEN value1 = (-1)↑uSign1 * s↑(uExp1-127) * <x0 . x1 x2 x3 ...> IF <x0, x1, ...> = <uHighHalf2, uLowHalf2> THEN value2 = (-1)↑uSign2 * s↑(uExp2-127) * <x0 . x1 x2 x3 ...> i.e. <uSign1, uExp1, uHighHalf1, uLowHalf1> is in proper format for immediate repacking, as is <uSign2, uExp2, uHighHalf2, uLowHalf2> } {**************************************************************************** Repack routine entry: TOS = | arg1H | STK = | ~ | --> | arg1L | uSign1 holds [0..14]=0, [15..15]=sign result uExp1 holds [0..15]=expResult, excess 127, possibly negative (if x0, x1, ... are the bits of <uHighHalf1,uLowHalf1>, then the represented value (exclusive of sign) is <x0. x1 x2 ...>*2↑(uExp1-127)) <uHighHalf1,uLowHalf1> holding upper 32 bits of fraction part of result, may contain leading zeros. uStickyBit is non zero if any bits to right of <uHighHalf1, uLowHalf1> are non zero exits with: TOS = |result1H | STK = | ~ | --> |result1L | } {Issues concerning the following algorithm are discussed in my notebook [Sturgis] for 28June82 page 3, 2 July page 6, and 7 July page 7} {watch out for rounding issues on ZeroResult} {in the following, nominal value is the result uncorrected for roundoff} {nominal value = (-1)↑uSign1 * <uHighHalf1[0] . uHighHalf1[1] ... > * 2↑(uExp1-127)} RePackC2: {delay} c2; RePackC3: {delay} c3; RePackC1: T ← uHighHalf1, c1; Q ← uLowHalf1 c2; Ybus ← T or Q, ZeroBr, c3; {nominal value = (-1)↑uSign1 * <T[0].T[1] ... Q[0] ...> * 2↑(uExp1-127)} TT ← uExp1, BRANCH[$, ZeroToNorm], c1; TT ← TT-2, c2; Ybus ← TT, NegBr, c3; {nominal value = (-1)↑uSign1 * <T[0].T[1] ... > * 2↑(TT+2-127)} NormLoop: Ybus ← T, NegBr, BRANCH[$, LowExp], c1; TT ← TT-1, NegBr, BRANCH[$, Normed], c2; T ← DLShift1 T, SE ← 1, BRANCH[NormLoop, SmallNumberC1], c3; {at Normed: nominal value = (-1)↑(uSign1) * <T[0].T[1]. ...> * 2↑(TT+3-127) and T[0] = 1, therefore nominal exponent = TT+2, and nominal fraction = T[1]...Q[7]} {at SmallNumber: nominal value = (-1)↑(uSign1) * <T[0].T[1]. ...> * 2↑(TT+2-127) and TT = -1, therefore nominal fraction = T[1]...Q[7], and nominal exponent = 1 if T[0] = 1, else 0. i.e. nominal exponent = T[0]} {at LowExp: nominal value = (-1)↑(uSign1) * <T[0].T[1]. ...> * 2↑(TT+2-127) and TT < 0} {*********************} {at LowExp: nominal value = (-1)↑(uSign1) * <T[0].T[1]. ...> * 2↑(TT+2-127) and TT < 0} {we will shift right one bit, and add 1 to TT, until TT = -1, then go to small number} {NOTE: this code is very painful for an exponent of 1, maybe I should avoid ariving here under those conditions?} LowExp: Rx ← 25'd, CANCELBR[$], c2; Ybus ← TT + Rx, NegBr, c3; Rx ← 1, BRANCH[$, VeryLowExp], c1; Q ← ~Q, {to allow for complementing on right shifts} c2; TT ← -TT-1, L0 ← L0.rePack1,CALL[DeNormC1] c3; {*********************} {at VeryLowExp, rounding to nearest can not produce any significant bits, however, fraction is known to be non zero, also Rx = 1} VeryLowExp: GOTO[FPTrapsC3], c2; {following is approx code if we did not trap on denormalized results VeryLowExp: Q ← 0, c2; T ← 0, c3; Rx ← 200'b, GOTO[inexact], c1;} {*********************} {nominal value = (-1)↑(uSign1) * <T[0].T[1]. ...> * 2↑(TT+2-127) and TT = -1, therefore nominal fraction = T[1]...Q[7], and nominal exponent = 1 if T[0] = 1, else 0. i.e. nominal exponent = T[0]} {upon entry from LowExp, TT is garbage, but above facts hold true} {note: following code would be used if we did not trap on denormalized results, and further, even if we do trap un denormalized results, there is exactly one case that goes through this code that does not trap, namely, a number which when rounded rounds up to a non denormalized number. SInce I wrote this code before understanding that I had to provide traps on denormalized results, I have decided to keepit..} {exit from the following has nominal exponent-3 in TT. Also a 1 bit in T[0], so that subsequent rounding will cause a carry overflow if rounding carrys into T[0]} SmallNumberC1: {delay} c1; SmallNumberC2: {delay} c2, at[L0.rePack1,10, DeNormRets]; SmallNumberC3: TT ← RRot1 1, c3; TT ← LRot1 (TT and T), {TT ← nominal exponent = T[0] } c1; Rx ← RRot1 1, c2; T ← T or Rx, {T[0] ← 1}, c3; TT ← TT - 3, {normed wants TT to hold nominal exponent - 3} c1; GOTO[Normed], c2; {*********************} {nominal value = (-1)↑(uSign1) * <T[0].T[1]. ...> * 2↑(TT+3-127) and T[0] = 1, therefore nominal exponent = TT+3, and nominal fraction = T[1]...Q[7]} {also entered from SmallNumberSmallNumber, arranged so that nominalFraction = <T[1]...>, T[0] = 1, and nominal exponent = TT+3} Normed: CANCELBR[$], c3; , c1; {**************************************************************************** rounding code (rounds to nearest) enter with L0 prepared for return. uSticky prepared data in T..Q if inexact result, will generate trap, or set sticky register bit, depending on contents of sticky register. ****************************************************************************} Round: Ybus ← uStickyBit, NZeroBr, c2; Rx ← 377'b, BRANCH[RoundA, RoundB], c3; RoundA: GOTO[RoundC], c1; RoundB: Q ← Q or 1, GOTO[RoundC], c1; RoundC: Ybus ← Q and Rx, ZeroBr, c2; Rx ← 200'b, BRANCH[Inexact, RoundExit1], c3; {in following we use TOS, which will eventually be restored} Inexact: Rx ← 10, c1; Rx ← Rx or uFLmode, c2; , c3; Ybus ← Rx, NegBr, c1; uFLmode ← Rx, BRANCH[FLQinexok, FLQinexnok], c2; FLQinexnok: GOTO[ufnZ12], c3; FLQinexok: Rx ← 200'b, c3; {now we round to nearest} Q ← Q + Rx, CarryBr, c1; Rx ← 177'b, BRANCH[$, inexact1], c2; Ybus ← Q and Rx, ZeroBr, c3; Rx ← LShift1 200'b, SE ← 0, BRANCH[RoundExit2, $], c1; Q ← Q and ~ Rx {Q[7] ← 0}, GOTO[RoundExit], c2; {roundoff carried across word boundary} inexact1: T ← T + 1, CarryBr, {overflowBr since T[0]=1} c3; BRANCH[RoundExit2A, $], c1; TT ← TT + 1 {roundoff overflowed, adjust exponent}, GOTO[RoundExit], c2; RoundExit2A: GOTO[RoundExit], c2; RoundExit1: {delay} c1; RoundExit2: , c2; RoundExit: , c3; {now we check for overflow and underflow} TT ← TT+3, c1; Rx ← 376'b, c2; Ybus ← Rx-TT, NegBr, {branches if TT >= 377'b} c3; Ybus ← TT, ZeroBr, BRANCH[$, FPTrapsC2], {overflow} c1; BRANCH[finalPack, FPTrapsC3], {underflow} c2; ZeroToNorm: TT ← 0, GOTO[ZeroFractionC3], c2; RepackExact0: uStickyBit ← TT ← 0, GOTO[ZeroFraction], c3; ZeroFractionC3: {delay} c3; ZeroFraction: T ← 0, c1; Q ← 0, GOTO[finalPack], c2; {result sign = uSign1, result exp = TT, result fraction = <T[1]...Q[7]>, T[0] = 1} finalPack: {and prepare for entry to CCSubr } TOS ← 377'b, c3; Q ← Q and ~TOS, {bottom 8 bits of final result} c1; TOS ← T and TOS, {next 8 bits of final result} c2; TOS ← Q or TOS, c3; TOS ← TOS LRot8, c1; uNewValLo ← TOS, {low word of result} c2; TT ← TT LRot8, c3; TT ← RRot1(TT or uSign1), {top 9 bits of final result} c1; T ← T LRot8, c2; TOSH ← T and 177'b, {next 7 bits of final result} c3; TOSH ← TOSH or TT, L3Disp, c1; uNewValHi ← TOSH, DISP4[fptQdone], c2; Q ← LS4FptType, c3, at[L3.FunUFirst, 10, fptQdone]; Bank ← EmuBank, L1 ← L1.fixFV, c1; L3 ← L3.FptArg1{fpt}, c2; CROSS[CCEntry], c3; FprepufnA3: GOTO[ufnZ12], c3; FprepufnB3: GOTO[ufnZ12], c3; FprepufnC3: GOTO[ufnZ12], c3; FprepufnD3: GOTO[ufnZ12], c3; FPTrapsC2: CANCELBR[ufnZ32], c2; FPTrapsC3: GOTO[ufnZ12], c3; { E N D }