{File name:  LispFPTSpec.mc
Last edited by cal         27-Dec-83 17:06:07 
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
	}

@FPLUS2:	opcode[350'b],
	uTOS ← TT ← TOS, CALL[FptPrep],{L2 ← 10'b}	c1;

@FDIFFERENCE:	opcode[351'b],
	uTOS ← TT ← TOS, CALL[FptPrep],{L2 ← 11'b}	c1;

@FTIMES2:	opcode[352'b],
	uTOS ← TT ← TOS, CALL[FptPrep],{L2 ← 12'b}	c1;

@FQUOTIENT:	opcode[353'b],
	uTOS ← TT ← TOS, CALL[FptPrep],{L2 ← 13'b}	c1;

@FGREATERP:	opcode[362'b],
	uTOS ← TT ← TOS, CALL[FptPrep], L2 ← L2.FptCmp,	c1;

FptPrep:
	uTOSH ← Rx ← TOSH, L3 ← L3.FptArg2,	c2;

	CALL[FptUnpack],	c3;

	uExp2 ← Rx, ZeroBr,	c3, at[L3.FptArg2, 10, FptUnpackRet];

	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 + 0],	c1;
	L3 ← L3.FptArg1,	c2;
	TT ← MD,	c3;
	
	MAR ← [rhS, S - 1],	c1;
	CANCELBR[$, 2],	c2;
	Rx ← MD, CALL[FptUnpack],	c3;

	uExp1 ← Rx, ZeroBr,	c3, at[L3.FptArg1, 10, FptUnpackRet];

	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;

{	FptUnpack Subroutine	}
	{on entry:
	    Rx holds high
	    TT holds low
	 on exit:
	     TOSH holds high
	     TOS holds low
	     TT holds sign
	     Rx holds exponent
	     Q holds 0FF
	 will page fault if page holding Fpt value not resident
	 }

FptUnpack:
	MAR ← Q ← [TT, Rx + 0],	c1;{not mem ref, byte merge}
	rhTT ← Rx LRot0, 	c2;
	Rx ← Q, rhRx ← MDSTYPEspaceReal,	c3;

	Rx ← Rx LRot8,	c1;
	Rx ← Rx RShift1, SE←1, 	c2;
	,	c3;

	MAR ← [rhRx, Rx], Rx ← FloatpType + 0,	c1;
	,	c2;
	Q ← MD xor Rx,	c3;

	,	c1;
	Ybus ← Q - 1, PgCarryBr,	c2;
	Q ← 0FF, BRANCH[$, FptNotFpt],	c3;

	Map ← [rhTT,TT], L0 ← L0.xRedoFpt,	c1;
	L1 ← L1.fixFV, 	c2;
	Rx ← rhRx ← MD, XRefBr,	c3;

	MAR ← [rhRx, TT + 0], BRANCH[FptRemap, $],	c1, at[L0.xRedoFpt, 10, RxMapFixCaller];
	,	c2;
	TOSH ← MD,	c3;

	MAR ← [rhRx, TT + 1],	c1;
	TT ← LRot1 TOSH, CANCELBR[$, 2],	c2;
	TOS ← MD,	c3;

	Rx ← TT LRot8 and Q, {exponent}, L3Disp,	c1;
	TT ← TT and 1, {the sign bit} RET[FptUnpackRet],	c2;

FptRemap:
	CALL[RLxMapFix],	c2;



{****************************************************************************
 
  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: 	TOS ← uStickyReg,	c1;
	TOS ← TOS or 1, NegBr,	c2;
	uStickyReg ← TOS, BRANCH[$, inexactTrap],	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 }
	Rx ← 377'b,	c3;

	Q ← Q and ~Rx, {bottom 8 bits of final result}	c1;
	Rx ← T and Rx, {next 8 bits of final result}	c2;
	Rx ← Q or Rx,	c3;

	Rx ← Rx LRot8,	c1;
	uNewValLo ← Rx, {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;
	TOS ← T and 177'b, {next 7 bits of final result}	c3;

	TOS ← TOS or TT, L1 ← L1.fixFV,	c1;
	uNewValHi ← TOS, L3 ← L3.FptArg1{fpt},	c2;
	Q ← LS4FptType, GOTO[CCSubr],	c3;

{	return from compare: 
	TOS =    0  =>  args equal
	TOS = +KTval  =>  arg1 bigger
	TOS =   0  =>  arg2 bigger
}

cmpExit3: {result not Floating point, no need to create cell }
	TOSH ← 0,	c3;

	S ← S - 2, L2 ← L2.0,	c1;
	PC ← PC + PC16, IBDisp,	c2;
	DISPNI[OpTable], L2 ← L2.0,	c3;



FPTufn:	{early debugging exit}
	GOTO[ufnX3],	c2;

FptNotFpt:	{one or more non-FloatType arg}
	GOTO[ufnZ2],	c1;

FprepufnA3:
	GOTO[ufnZ1],	c3;

FprepufnB3:
	GOTO[ufnZ1],	c3;

FprepufnC3:
	GOTO[ufnZ1],	c3;

FprepufnD3:
	GOTO[ufnZ1],	c3;

inexactTrap: GOTO[FPTrapsC2],				c1;
	
FPTrapsC2:	CANCELBR[ufnZ3],	c2;

FPTrapsC3:	GOTO[ufnZ1],	c3;

	{ E N D }