:TITLE[MesaFP];	*DO MESA FLOATING POINT by Jim Boyce

%Edit by Ed Fiala 20 March 1981: put in Pilot conditionals; bum 2
registers.
%

%Floating point numbers are represented in two different formats.  Arguments
on the stack are IEEE single precision reals with the following format:
	bit 0	sign (1 means negative)
	1:8	exponent biased by 127
		(exponent of 0 with a fraction of 0 is true 0;
		 exponent of 0 with non-0 fraction is denormalized;
		 exponent of 377 with a fraction of 0 is infinity;
		 exponent of 377 with non-0 fraction is Not-A-Number)
	9:31	fraction
		(implicitly preceded by '1.' if non-0 and normalized.)
These numbers appear on the stack with the word holding bits 0-15 nearer to
the top of stack.  Most operations unpack the operands into a format that is
easier to work with.  This format uses four words interpreted as follows:
	Sign	bit 0 is the sign, bits 1-15 are undefined.
	Exp	exponent (Biased by 127)
	Frac	The fraction.  When unpacked, the leading one appears in
		Frac[1]; when about to be packed again, the leading bit is in
		Frac[0],  Frac[37] is always a StickyBit (the inclusive or of
		all the remaining bits).  
	FracH	16 high order bits of Frac.
	FracL	16 low order bits of Frac.

Twelve registers hold three floating point numbers in unpacked form.  Two of
the numbers hold arguments and have registers names with 1's or 2's in them.
The other is a number called Temp.  Numbers are usually referred to by index
(SB or DB).  Arg1 has index 2, Arg2 - 3, and Temp - 0.
%

:IF[AltoMode]; ********************************************
*xfMY is available; could make xfOTPReg available by using MNBR the
*way the Pilot conditionals use it.
RV[Sign,IP[zBuf]];	RV[Exp,IP[xBuf]];	RV[FracH,IP[yBuf]];	RV[FracL,64];
RV[TSign,IP[zBuf]];	RV[TExp,IP[xBuf]];	RV[TFracH,IP[yBuf]];	RV[TFracL,64];
RV[Sign1,IP[zBuf2]];	RV[Exp1,IP[xBuf2]];	RV[Frac1H,IP[yBuf2]];	RV[Frac1L,66];
RV[Sign2,IP[zBuf3]];	RV[Exp2,IP[xBuf3]];	RV[Frac2H,IP[yBuf3]];	RV[Frac2L,67];

RV[FracLL,IP[xfMX]];		*Low order word in fraction, Used by Unnorm,
				*(RoundCard), and Multiply.
RV[Sticky,75];			*Bit 0 InexactResultTrapEnable
				*Bit 15 'Has InexactResult happened?'.
RV[FlCode,IP[xfXTPreg]];	*Used to control program flow ('computed GoTos')
RV[CCTemp1,IP[yBuf1]];
RV[CCTemp2,IP[xBuf1]];		*Used only in Unnorm.
RV[LoopCount,IP[yBuf1]];	*Used by Multiply and Divide.
RV[FPTemp1,IP[zBuf1]];		*Used to control Unnorm.
RV[FPTemp2,IP[xBuf1]];		*Used to set DB, SB, and StkP, throughout.

*431b mi including the two Misc alpha-byte dispatch locations overwritten
*in MesaX.  Placement is primarily on page 16 (reserving 23 locations for the
*kernel code which might be present) with the rest on page 17.
Set[FlPage0,16];	*357b mi (not pages 4 to 7)
  Loca[UnnormDisp,FlPage0,40];
  Loca[UnpackRet,FlPage0,60];
  Loca[RoundDisp,FlPage0,100];
  Loca[FixDisp,FlPage0,120];
  Loca[UnnormRet,FlPage0,140];
Set[FlPage3,17];	*  4b mi
Set[FlPage4,17];	* 25b mi
Set[FlPage5,16];	* 12b mi
Set[FlPage6,16];	*  3b mi
Set[FlPage7,17];	*  2b mi
:ELSE; ****************************************************
RV[Sign,70];	RV[Exp,44];	RV[FracH,50];	RV[FracL,64];
RV[TSign,70];	RV[TExp,44];	RV[TFracH,50];	RV[TFracL,64];
RV[Sign1,72];	RV[Exp1,46];	RV[Frac1H,52];	RV[Frac1L,66];
RV[Sign2,73];	RV[Exp2,47];	RV[Frac2H,53];	RV[Frac2L,67];

RV[FracLL,56];		*Low order word in fraction, Used by Unnorm,
			*(RoundCard), and Multiply.
RV[Sticky,65];		*Bit0 InexactResultTrapEnable
			*Bit15 'Has InexactResult happened?'.
RV[FlCode,57];		*Used to control 'computed GoTos'
RV[CCTemp1,71];		*Used only in Unnorm.
RV[CCTemp2,17];		*Used only in Unnorm.
RV[LoopCount,71];	*Used by Multiply and Divide.
RV[FPTemp1,45];		*Used to control Unnorm.
RV[FPTemp2,17];		*Used to set DB, SB, and StkP, throughout.

*433b mi placed primarily on page 1 with the rest on page 4.
Set[FlPage0,1];		*361b mi (not pages 4 to 7)
  Loca[UnnormDisp,FlPage0,40];
  Loca[UnpackRet,FlPage0,60];
  Loca[RoundDisp,FlPage0,100];
  Loca[FixDisp,FlPage0,120];
  Loca[UnnormRet,FlPage0,140];
Set[FlPage3,13];	*  4b mi
Set[FlPage4,13];	* 25b mi
Set[FlPage5,1];		* 12b mi
Set[FlPage6,1];		*  3b mi
Set[FlPage7,1];		*  2b mi
:ENDIF; ***************************************************

%Coding conventions.

Misc bytecodes with alpha in [20b to 37b] are floating point
operations.  The 1st mi below is the Misc dispatch table entry for
alpha in this range.  For Alto Mesa, alpha is saved in xfOTPReg,
where it is the trap parameter if the FP operation traps; for Cedar
MNBR holds alpha and 400b+alpha determines the trap dispatch.  T is
loaded with 30b, which will be stored in SALUF as the A + A + Cy0
ALU operation.

Two different subroutine linkages are used in this code.  Call[] and Return
is used for bottom level subroutines.  The other linkage, GoTo[] and
Dispatch[FlCode,,], where FlCode holds an 8-bit number encoding various
return addresses, is used for several long routines.  The return mi appears
where one would expect it, with an At[] to place it properly in RAM.
%

:IF[AltoMode]; ********************************************
*Overwrite the two MISC dispatch mi to setup the branch to this code.
Set[FlPntLoc,Add[MiscDisp0,17]];
	xfOTPReg ← T, LoadPage[FlPage0], At[MiscDisp0,1];
	Dispatch[RTemp,14,4], At[FlPntLoc];
OnPage[FlPage0];
:ELSE; ****************************************************
	LoadPage[FlPage0], At[MiscDisp0,1];
	MNBR ← RTemp;	*MNBR not smashed by BBFB
OnPage[FlPage0];
	Dispatch[RTemp,14,4];
:ENDIF; ***************************************************
	T ← 30C, Disp[.+1];

	FlCode ←  0C, GoTo[Unpack], DispTable[20];	*FAdd
	FlCode ← 76C, GoTo[Unpack];			*FSub
	FlCode ← 2C, GoTo[Unpack];			*FMul
	FlCode ← 4C, GoTo[Unpack];			*FDiv
	FlCode ← 14C, GoTo[Unpack];			*FComp
	FlCode ← 31000C, GoTo[FixA];			*Fix
	SALUF ← T, GoTo[Float];				*Float
	FlCode ← 32400C, GoTo[FixA];			*FixI
	FlCode ← 35000C, GoTo[FixA];			*FixC
	T ← Sticky, LoadPage[FlPage4], GoTo[FSticky];	*FSticky
	T ← SStkP, GoTo[FloatTrp1];			*FRem not implemented
	FlCode ← 21000C, GoTo[FixA];			*Round
	FlCode ← 22400C, GoTo[FixA];			*RoundI
	FlCode ← 25000C, GoTo[FixA];			*RoundC
	T ← SStkP, GoTo[FloatTrp1];			*SetS not implemented
	T ← SStkP, GoTo[FloatTrp1];			*Not implemented

*One mi subroutines

SetSALUF:
	SALUF ← T, Return;

SetSB:	SB ← FPTemp2;
	BBFBX, Return;

SetSBSign:
	SB[Sign] ← T,  Return;

SetSBFracH:
	SB[FracH] ← T, Return;

SetSBFracL:
	SB[FracL] ← T, Return;

SetSBExp:
	SB[Exp] ← T, Return;

%Floating Point number conversions.

Entries are Unpack, Pack0, Pack0A, and Renorm.

Unpack pops arguments off of the stack and unpacks them into Arg1 and Arg2.
The argument at the top of the stack is put in Arg1.  (Note that the single
argument of a monadic operation is put in Arg2 (!?).)  FlCode is used to
distinguish between single- and double-argument operations.  Unpack acts as a
filter, traping to MesaCode on arguments that the microcode cannot handle--
Unnormalized numbers, Infinities, and NotANumbers.

Pack0 pushes a Zero of the appropriate sign onto the stack.

Renorm Rightshifts the fraction SB[FracH],,SB[FracL] until SB[FracH][0] is a
onebit.  It subtracts the number of positions shifted from SB[Exp].  Then it
performs range checks and pushes a number onto the stack.
%
OnPage[FlPage0];

Unpack:	FPTemp2 ← 60C, Call[SetSALUF];	*Select arg 2
UnpackA:
	T ← Stack, Call[SetSB];
	SB[FracH] ← 40000C, Call[SetSBSign];
	T ← LdF[Stack,1,10];
	SB[Exp] ← T;
	T ← LSh[Stack&-1,7], GoTo[Non0,ALU#0];
	  T ← (Stack&-1) or T;
	  SB[FracH] ← T, GoTo[DenormTrap,ALU#0];
	  SB[FracL] ← T, GoTo[UnpackB];
Non0:	LU ← (SB[Exp]) xor (377C);
	T ← (RSh[Stack,11]) or T, GoTo[NaNTrap,ALU=0];
	SB[FracH] ← (SB[FracH]) or T;
	SB[FracH] ← (SB[FracH]) and not (100000C);
	T ← LSh[Stack&-1,7], Call[SetSBFracL];
UnpackB:
	FlCode ← (FlCode) + 1, Skip[R Odd];
	  FPTemp2 ← (FPTemp2) - 1, GoTo[UnpackA];	*Select arg 1
	Dispatch[FlCode,14,3];
	T ← SB[FracH], Disp[@UnpackRet];


Pack0:	T ← (SB[Sign]) and (100000C), GoToP[.+1];
OnPage[FlPage4];
	Stack&+1 ← 0C, GoTo[PackA];

OnPage[FlPage0];
NormStep:
	SB[Exp] ← (SB[Exp]) - 1;
	SB[FracL] ← (SB[FracL]) SALUFOp T, Task;
	SB[FracH] ← (SB[FracH]) SALUFOp T, UseCoutAsCin;
ReNorm:	SB[FracH], GoTo[NormStep,R>=0];
	Call[NoRound];			***This is a noop for tasking
*Pack non-0 begins here
	LU ← (SB[FracL]) and (177C), Call[RoundFrac];
	LU ← (SB[Exp]) - 1;
	LU ← (SB[Exp]) - (377C), GoTo[UnderFlowTrap,ALU<0];
	T ← RSh[SB[FracL],10], GoTo[OverFlowTrap,ALU>=0];
	T ← (LSh[SB[FracH],10]) or T;
	Stack&+1 ← T, LoadPage[FlPage4];
	T ← LdF[SB[FracH],1,7];
OnPage[FlPage4];
	T ← (LSh[SB[Exp],7]) or T;
	LU ← SB[Sign];
PackA:	Stack&+1 ← T, LoadPageExternal[opPage3], Skip[ALU>=0];
	  Stack ← (Stack) or (100000C), GoToExternal[P7TailLoc];
NormRetx:
	GoToExternal[P7TailLoc];

%Shifting Fractions.

Entry is Unnorm.

Unnorm leftshifts the fraction DB[FracH],,DB[FracL],,FracLL by FPTemp1
positions.  FracLL[15] is treated as a StickyBit.  FracLL is assumed to be
Zero on entry.  The first part of the code reaches a point from which the
result can be reached by swapping words without any more shifts.  Then the
swaps are performed.
%

OnPage[FlPage0];
GetCC1:	CycleControl ← CCTemp1, Return;
GetCC2:	CycleControl ← CCTemp2, Return;

Unnorm:	T ← (LdF[FPTemp1,14,4]) - 1, Call[NoRound];
	CCTemp1 ← T, BBFBX;
	CCTemp1 ← (CCTemp1) and (17C), Skip[ALU>=0];
	  FracLL ← 0C, Goto[Unnorm0];
	CCTemp2 ← 16C;
	CCTemp2 ← (CCTemp2) - T, Call[GetCC1];
	T ← WFA[DB[FracL]];
	FracLL ← T, Call[GetCC2];
	DB[FracL] ← RF[DB[FracL]], Call[GetCC1];
	T ← WFA[DB[FracH]];
	DB[FracL] ← (DB[FracL]) or T, Call[GetCC2];
	DB[FracH] ← RF[DB[FracH]];
Unnorm0:
	LU ← LdF[FPTemp1,10,2];
	Dispatch[FPTemp1,12,2], Skip[ALU#0];
	  T ← DB[FracL], Disp[@UnnormDisp];
	FracLL ← 1C, GoTo[UnnormL];

	LU ← FracLL, LoadPage[FlPage6], At[UnnormDisp,1];	*Shift 1 word
	FracLL ← T, SkipP[ALU=0];
OnPage[FlPage6];
	  FracLL ← (FracLL) or (1C);
	T ← DB[FracH], LoadPage[FlPage0];
	DB[FracL] ← T, GoToP[UnnormH];

	LU ← (FracLL) or T, At[UnnormDisp,2];	*Shift 2 words
	T ← DB[FracH], FreezeResult;
	FracLL ← T, GoTo[UnnormL,ALU=0];
	FracLL ← (FracLL) or (1C), GoTo[UnnormL];

UnnormLL:
	FracLL ← 1C, At[UnnormDisp,3];		*Shift more than 2 words
UnnormL:
	DB[FracL] ← 0C;
UnnormH:
	DB[FracH] ← 0C, CallX[CNoRound], At[UnnormDisp,17];
@UnnormDisp:
	Dispatch[FlCode,12,2], At[UnnormDisp,0];	*No more shifting
	T ← FracLL, Disp[@UnnormRet];

%Rounding, Negation, and FloatTrap.

Rounding happens at a particular position using the following bits to
determine the direction of rounding.  If the rounding bits are all Zero, then
the result is exact, and no rounding takes place.  Otherwise, round to the
nearer representable number.  If the rounding bits put the number exactly
halfway between two possible results, round to the one with a Zero in the
rounding position.

RoundFrac rounds SB[FracH],,SB[FracL] at SB[FracL][7] using SB[FracL][10:17]
as rounding bits.  (The actual add occurs at SB[FracL][10] to simplify the
tests.)

RoundCard rounds SB[FracH],,SB[FracL] at SB[FracL][17] using FracLL[0:17] as
rounding bits.

NegFrac performs a 2's complement negation on SB[FracH],,SB[FracL].

Entries are RoundFrac, RoundCard, NegFrac, and CNoRound.
%
OnPage[FlPage0];
RoundFrac:
	Dispatch[SB[FracL],7,3], GoTo[FRoundUp,ALU#0];
	T ← SB[Sign], Disp[NoRound];
NoRound:
	Return, At[RoundDisp,0];
FRoundUp:
	T ← SB[Sign];
	SB[FracL] ← (SB[FracL]) + (200C), At[RoundDisp,6];
RoundUp1:
	SB[FracH] ← (SB[FracH]) + 1, UseCoutAsCin;
	SB[Exp] ← (SB[Exp]) + 1, UseCoutAsCin, Skip[Carry'];
	  SB[FracH] ← 100000C;
	Sticky, DblGoTo[InexactTrap,InexactNoTrap,R<0], At[RoundDisp,2];
	Return, At[RoundDisp,4];
CRoundUp:
	SB[FracL] ← (SB[FracL]) + 1, GoTo[RoundUp1];
CRoundDown:
	Sticky, DblGoTo[InexactTrap,InexactNoTrap,R<0];
InexactNoTrap:
	Sticky ← (Sticky) or (1C), GoTo[SetSBSign];

RoundCard:
	LU ← (FracLL) and not (100000C), GoTo[CNoRound,ALU=0];
	T ← SB[Sign], Skip[ALU=0];
	  FracLL, DblGoTo[CRoundUp,CRoundDown,R<0];
	SB[FracL], DblGoTo[CRoundUp,CRoundDown,R Odd];

NegFrac:
	SB[FracL] ← (SB[FracL]) xnor (0C);
	SB[FracH] ← (SB[FracH]) xnor (0C);
	SB[FracL] ← (SB[FracL]) + 1;
CNoRound:
	SB[FracH] ← (SB[FracH]) + 1, UseCoutAsCin, Return;

%For Alto Mesa, FloatTrap et al. store alpha in OTPReg, set T to
sFloatingPoint, and go to Kfcr which traps to MesaCode to try again
on this operation.  For Cedar Mesa, the parameter is 400 + alpha.
%
OnPage[FlPage0];
UnderFlowTrap:
	T ← SStkP, GoTo[FloatTrp1];
OverFlowTrap:
	T ← SStkP, GoTo[FloatTrp1];
InexactTrap:
	T ← SStkP, GoTo[FloatTrp1];
FixTrapA:
	T ← SStkP, GoTo[FloatTrp1];
FixTrapB:
	T ← SStkP, GoTo[FloatTrp1];
FixTrap:
	T ← SStkP, GoTo[FloatTrp1];
NaNTrap:
	T ← SStkP, GoTo[FloatTrp1];
DenormTrap:
	T ← SStkP, GoTo[FloatTrp1];
FloatTrap:
	T ← SStkP;
FloatTrp1:
	FPTemp2 ← T, Task;
	StkP ← FPTemp2;
:IF[AltoMode]; ********************************************
	LoadPageExternal[opPage3];
	T ← sFloatingPoint, GoToExternal[kfcrLoc];
:ELSE; ****************************************************
	T ← MNBR;
	RTemp ← T, LoadPage[opPage0];
	RTemp ← (RTemp) + (400C), GoToP[UndefTrap];	*400 + alpha
:ENDIF; ***************************************************

%Addition and subtraction are almost the same.  
 1) Unpack the arguments, Negate Arg2 if subtract, Check for Zero arguments.
 2) Determine which (if either) argument to shift.  Set DB gets that and SB
gets the other.
 3) Unnormalize the DB fraction.
 4) Add or subtract magnitudes, depending on the signs.
 5) Renormalize the result, push it on the stack and go on to the next operation.
%
@UnpackRet:
	Sign2 ← (Sign2) xor (100000C), At[UnpackRet,0];
	LU ← (Frac2H) and T, LoadPage[FlPage7], At[UnpackRet,1];
	T ←  Exp2, LoadPage[FlPage3], GoToP[Add0,ALU=0];
OnPage[FlPage7];
	T ← (Exp1) - T, LoadPage[FlPage0];
OnPage[FlPage3];
	FPTemp1 ← T, GoToP[.+3,ALU<0];
OnPage[FlPage0];
	  FPTemp2 ← (SB ← FPTemp2) + 1;
	  DB ← FPTemp2, GoTo[Unnorm];
	FPTemp2 ← (DB ← FPTemp2) + 1, Call[SetSB];
	FPTemp1 ← (Zero) - T, GoTo[Unnorm];


@UnnormRet:
	T ← SB[Sign], Skip[ALU=0], At[UnnormRet,0];
	  DB[FracL] ← (DB[FracL]) or (1C);
	SB[Exp] ← (SB[Exp]) + 1;
	LU ← (DB[Sign]) xor T;
	T ← DB[FracL], DblGoToP[SubFrac,AddFrac,ALU<0];

*The signs are equal;  add the fractions.  DB[FracL] is in T.
AddFrac:
	SB[FracL] ← (SB[FracL]) + T;
	T ← DB[FracH], FreezeResult;
	SB[FracH] ← (SB[FracH]) + T, UseCoutAsCin, GoTo[Renorm];

*The signs are different;  subtract the fractions.  DB[FracL] is in T.
SubFrac:
	SB[FracL] ← (SB[FracL]) - T;
	T ← DB[FracH], FreezeResult;
	SB[FracH] ← T ← (SB[FracH]) - T, UseCoutAsCin;
	LU ← (SB[FracL]) or T, GoTo[SubNeg,ALU<0];
SubNonNeg:
	GoTo[Sub0,ALU=0];
	GoTo[Renorm];

SubNeg:	SB[Sign] ← (SB[Sign]) xnor (0C), Call[NegFrac];
  	GoTo[ReNorm];

Sub0:	SB[Sign] ← T, LoadPage[FlPage4], GoTo[Pack0];

%Floating multiply.

 1) Unpack arguments, and check for Zero arguments.
 2) Set sign and exponent of the result.
 3) Shift arguments into position for a shift and add loop.
 4) Perform the shift and add loop.
 5) Renormalize and push result.
%
@FMul:	LU ← (Frac2H) and T, At[UnpackRet,2];
Mul0Test:
	T ← Sign2, GoTo[Mul0,ALU=0];
	FPTemp2 ← 0C, Call[SetSB];
	T ← (Sign1) xor T, Call[SetSBSign];
	T ← LSh[Frac2H,11];
	Frac2L ← (RSh[Frac2L,7]) or T;
	FracLL ← T ← 0C, Call[SetSBFracH];
	Frac2H ← RSh[Frac2H,7], Call[SetSBFracL];
	T ← Exp2;
	T ← (Exp1) + T;
	LoopCount ← 16C, Call[SetSBExp];
	SB[Exp] ← (SB[Exp]) - (176C), GoTo[MulLoop];

MulRet:	LU ← LHMask[SB[FracH]];
	T ← Frac1L, GoTo[MulDone,ALU#0];
	LoopCount ← 7C;
	Frac1H ← T, GoTo[MShift];

MulDone:
	LU ← FracLL;
MulDone1:
	GoToP[Renorm,ALU=0];
	SB[FracL] ← (SB[FracL]) or (1C), GoTo[Renorm];

MAdd:	T ← Frac2L;
	FracLL ← (FracLL) + T;
	T ← Frac2H, FreezeResult;
	TFracL ← (TFracL) + T, UseCoutAsCin, Task;
	TFracH ← (TFracH) + 1, UseCoutAsCin;
MulTest:
	LoopCount ← (LoopCount) - 1, GoTo[MulRet,R<0];
MShift:	FracLL ← (FracLL) SALUFOp T;
	TFracL  ← (TFracL)  SALUFOp T, UseCoutAsCin, Task;
	TFracH  ← (TFracH)  SALUFOp T, UseCoutAsCin;
MulLoop:
	Frac1H ← (Frac1H) SALUFOp T, DblGoTo[MAdd,MulTest,R<0];

%Floating point division.

 1) Unpack arguments, and check for Zero arguments.
 2) Set sign and exponent of the result.
 3) Shift arguments into position for a shift and subtract loop.
 4) Perform the shift and subtract loop.
 5) Renormalize and push result.
%
@FDiv:	LU ← (Frac2H) and T, At[UnpackRet,3];
	T ← Sign2, GoTo[Div0,ALU=0];
	FPTemp2 ← 0C, Call[SetSB];
	T ← (Sign1) xor T, Call[SetSBSign];
	SB[FracL] ← T ← 1C, Call[SetSBFracH];
	T ← (Exp2) - (177C);
	T ← (Exp1) - T;
	LoopCount ← 16C, Call[SetSBExp];
*Loop here
	LU ← (SB[FracL]) and (1C);
	T ← Frac2L, DblGoTo[DivSub,DivAdd,ALU#0];

DivSub:	Frac1L ← (Frac1L) - T, LoadPage[FlPage5];
	T ← Frac2H, FreezeResult;
OnPage[FlPage5];
	Frac1H ← (Frac1H) - T, UseCoutAsCin, GoTo[DivAnsBit];

OnPage[FlPage0];
DivAdd:	Frac1L ← (Frac1L) + T, LoadPage[FlPage5];
	T ← Frac2H, FreezeResult;
OnPage[FlPage5];
	Frac1H ← (Frac1H) + T, UseCoutAsCin;
DivAnsBit:
	SB[FracL] ← (SB[FracL]) SALUFOp T, UseCoutAsCin;
	LoopCount ← (LoopCount) - 1, GoTo[DivShift,R>=0];
	  LU ← LHMask[SB[FracH]];
	  T ← SB[FracL], LoadPage[FlPage0], GoTo[DivFinish,ALU#0];
	  SB[FracH] ← T, LoadPage[FlPage5];
OnPage[FlPage0];
	  LoopCount ← 10C;
OnPage[FlPage5];
DivShift:
	Frac1L ← (Frac1L) SALUFOp T;
	Frac1H ← (Frac1H) SALUFOp T, UseCoutAsCin, Return;

DivFinish:
	SB[FracL] ← LSh[SB[FracL],6], SkipP[R Even];
OnPage[FlPage0];
	  T ← Frac1H, GoTo[DivMore1];
	T ← Frac2L;
	Frac1L ← (Frac1L) + T;
	T ← Frac2H, FreezeResult, Task;
	T ← (Frac1H) + T, UseCoutAsCin;
DivMore1:
	LU ← (Frac1L) or T, GoTo[MulDone1];

%Arithmetic with Zeroes.

Add (subtract).  If one argument is 0, return the other.  If both are 0,
return 0 (negative 0 if both arguments are negative 0.)

Divide.  If denominator is 0, trap to MesaCode.

Multiply.  Return 0 of the appropriate sign.

Otherwise, do as with multiply.
%

OnPage[FlPage7];
Add0:	LU ← Frac1H, GoToP[.+1];
OnPage[FlPage3];
	LU ← Frac2H, LoadPage[FlPage4], Skip[ALU=0];
	  Stack&+2, GoToP[NormReturn];
	T ← Sign2, LoadPage[FlPage0], SkipP[ALU#0];
OnPage[FlPage4];
	  Sign1 ← (Sign1) and T, LoadPage[FlPage4], GoToP[Pack0];
AddArg10:
	FPTemp2 ← 60C, GoToP[.+1];
OnPage[FlPage0];
	SB ← FPTemp2;
	Exp2 ← (Exp2) + 1, BBFBX, GoTo[Renorm];

Div0:	LU ← (Frac2H) and (40000C);
	T ← 0C, DblGoTo[FloatTrap,Mul0Test,ALU=0];

Mul0:	Sign1 ← (Sign1) xor T, LoadPage[FlPage4], GoTo[Pack0];

%Floating Comparison.
Returns INTEGER -1 if arg1<arg2, 0 if arg1=arg2, and 1 if arg1>arg2
%
@FComp:	T ← Sign1, Task, At[UnpackRet,7];
	Stack&+3;
	LU ← (Sign2) xor T;
	T ← Stack&-2, LoadPage[FlPage4], GoTo[CompDiffSign,ALU<0];
	LU ← (Stack&+3) - T;
OnPage[FlPage4];
	T ← Stack&-2, FreezeResult;
	T ← (Stack&-1) - T, UseCoutAsCin, GoTo[CompNon0Test,ALU#0];
Comp0Test:
	Stack ← T, FreezeResult, Skip[ALU#0];
NormReturn:
	  LoadPageExternal[opPage3], GoTo[NormRetx];
	Sign2 ← (Sign2) xnor (0C), DblGoTo[.+3,.+2,Carry'];
CompNon0Test:
	Sign2 ← (Sign2) xnor (0C), Skip[Carry'];
	  Sign1, LoadPageExternal[opPage3], DblGoTo[CompL,CompG,R<0];
	  Sign2, LoadPageExternal[opPage3], DblGoTo[CompL,CompG,R<0];

CompG:	Stack ← 1C, GoToExternal[P7TailLoc];
CompL:	Stack ← (Stack) or not (0C), GoToExternal[P7TailLoc];

OnPage[FlPage0];
CompDiffSign:
	  T ← Frac1H, GoToP[.+1];
OnPage[FlPage4];
	  T ← (Frac2H) or T, GoTo[Comp0Test];


%Float LONG INTEGER to REAL
 1) Copy the argument into Frac1
 2) Check for Zero.
 3) Check sign, and negate Frac1 if negative.
 4) Set exponent and Renormalize.
%
OnPage[FlPage0];
Float:	T ← Stack&-1;
	FPTemp2 ← 40C, Call[SetSB];
	SB[FracH] ← T, Call[SetSBSign];
	T ← Stack&-1;
	LU ← (SB[FracH]) or T;
	SB[FracL] ← T, Skip[ALU#0];
	  LoadPage[FlPage4], GoTo[Pack0];
	LU ← (SB[Sign]) xnor (0C);
	SB[Exp] ← 236C, Skip[ALU<0];
	  Call[NegFrac];
	GoTo[ReNorm];

%Fix or Round from REAL to LONG INTEGER, INTEGER, or CARDINAL.
 1) Unpack the argument.
 2) Copy Frac1 into TempFrac and unnormalize TempFrac.
 3) Round, if appropriate (controlled by FlCode)
 4) Several things depending on the result type	(controlled by FlCode)
	LONG INTEGER		INTEGER			CARDINAL
	Negate Frac1, if	Check that Frac1H and	Negate Frac1, if
	Sign1 is negative.	Frac1L[0] are all 0.	Sign1 is negative.

				Negate Frac1, if	Check that Frac1H is 0.
				Sign1 is negative.
 5) Return result of the appropriate size (controlled by FlCode)
%

OnPage[FlPage0];
FixA:	FlCode ← (FlCode) or (11C), GoTo[Unpack];
	T ← SB[Exp], At[UnpackRet,5];
	FPTemp1 ← 235C;
	FPTemp1 ← (FPTemp1) - T;
	T ← SB[FracH], GoTo[FixTrap,ALU<0];
	SB[Sign] ← (SB[Sign]) xor (100000C), Skip[ALU#0];
	  FlCode ← LCy[FlCode,10], GoTo[Fix0];
	DB ← FPTemp2;
	FlCode ← LCy[FlCode,10], GoTo[Unnorm];

	LU ← FracLL, Call[RoundCard], At[UnnormRet,2];
	FlCode, DblGoTo[FixTest015,FixTestSign,R Odd], At[UnnormRet,3];

FixTestSignA:
	SB[Sign], DblGoTo[.+3,.+2,R<0];
FixTestSign:
	SB[Sign], Skip[R<0];
	  Call[NegFrac];
Fix0:	Dispatch[FlCode,14,3];
	T ← SB[FracL], Disp[FixDoneShort];
FixTest015:
	LU ← SB[FracH], At[FixDisp,5];
	T ← SB[FracL], GoTo[FixTrapB,ALU#0];
	FlCode, DblGoTo[FixTest16,FixDoneShort,R Odd];

FixTest16:
	SB[FracL], DblGoTo[FixTrapA,FixTestSignA,R<0];

FixDoneShort:
	LoadPageExternal[opPage3], GoTo[EndFix], At[FixDisp,2];

	Stack&+1 ← T, At[FixDisp,1];
	T ← SB[FracH], LoadPageExternal[opPage3];
EndFix:	Stack&+1 ← T, GoToExternal[P7TailLoc];


%FSticky is used to read and set the InexactResultTrapEnable and the
InexactResult Bit.  It swaps Stack and Sticky.
%
OnPage[FlPage0];
FSticky:
	MNBR ← Stack, Stack ← T, NoRegILockOK, GotoP[.+1];
OnPage[FlPage4];
	T ← MNBR;
	Sticky ← T, LoadPageExternal[opPage3], GoTo[NormRetx];

:END[MesaFP];