{File name LispUnboxed.mc
Description:  DandeLion InterLisp Emulator Unboxed Floating Point OpCodes
Author: Charnley
Last modified: Charnley               5-Jun-84 16:23:45
Created:   1-Jun-84 11:02:56
}

{	@UNBOX2	two byte opcode = 355
	Two argument opcodes
	Alpha byte defines one of the following operations:
	{10 clicks}	0  UFADD  unboxed floating add
	{10 clicks}	1  UFSUB  unboxed floating subtract {1st minus 2nd}
	{10 clicks}	2  UFISUB  unboxed floating subtract {2nd minus 1st}
	{10 clicks}	3  UFMULT  unboxed floating multiply
	{ufn}	4  UFDIV  unboxed floating divide
	{11 clicks}	5  UGREAT  unboxed floating compare {returns T or NIL}
	{11 clicks}	6  UMAX  unboxed floating maximum 
	{11 clicks}	7  UMIN  unboxed floating minimum 

	@UNBOX1	two byte opcode = 354
	Single argument opcodes
	Alpha byte defines one of the following operations:
	{39 clicks}	0  UTOB  convert unboxed to boxed {always returns boxed floating point number}
	{sm 8, fl 12, fx ??} 1  BTOU  convert boxed to unboxed {will coerce fixed point numbers}
	{ 4 clicks}	2  UABS  unboxed floating absolute value
	{ 4 clicks}	3  UNEG  unboxed floating negative value
}

Set[UF2.add, 0],
Set[UF2.sub, 1],
Set[UF2.isub, 2],
Set[UF2.mult, 3],
Set[UF2.div, 4],
Set[UF2.great, 5],
Set[UF2.max, 6],
Set[UF2.min, 7],

Set[UF1.utob, 0],
Set[UF1.btou, 1],
Set[UF1.abs, 2],
Set[UF1.neg, 3];

{Set[L3.utob, 7];{for CreateCell}}


{@UNBOX2:	opcode[355'b],
	Bank ← LUBank,	c1;
	uTOS ← TOS,	c2;
	uTOSH ← TOSH, CROSS[UB2Start],	c3;
}

	FloatNop,	c1, at[UB2Start];{clear pending unloads}
	FloatNop,	c2;
	,	c3;

	FloatMode.RN.AI.FAST, FloatFLOW,	c1;
	FloatAB ← TOSH LRot0,	c2;
	Xbus ← ibNA, XDisp, L2 ← 0,	c3;

	MAR ← [rhS, S - 1], DISP4[FOP2op],	c1;
	FloatAB ← TOS LRot0, CANCELBR[$, 2],	c2, at[UF2.add, 10, FOP2op];
	TT ← FloatA ← MD, FLPlus, GOTO[FOPtail],	c3;

	FloatAB ← TOS LRot0, CANCELBR[$, 2],	c2, at[UF2.sub, 10, FOP2op];
	TT ← FloatA ← MD, FLAMinusB, GOTO[FOPtail],	c3;

	FloatAB ← TOS LRot0, CANCELBR[$, 2],	c2, at[UF2.isub, 10, FOP2op];
	TT ← FloatA ← MD, FLBMinusA, GOTO[FOPtail],	c3;

FOPtail:
	MAR ← [rhS, S + 0],	c1;
	,	c2;
	Rx ← FloatA ← MD,	c3;

	FloatStartFlow,	c1;
	,	c2;
	,	c3;

	PC ← PC + 1,	c1;
	FloatUnloadS, Float.M,	c2;
	FloatUnloadS, Float.M,	c3;

	{Q ← PPort, }GOTO[FOPend],	c1;
FOPend:
	{Ybus ← Q, YDisp},	c2;
	S ← S - 2, DISP4[illegal?, 9], L2Disp,	c3;

	Xbus ← ib, DISP4[FOP2end],	c1, at[9, 10, illegal?];
	TOSH ← FloatResult, GOTO[FOP2normend],	c2, at[UF2.add, 10, FOP2end];
	TOSH ← FloatResult, GOTO[FOP2normend],	c2, at[UF2.sub, 10, FOP2end];
	TOSH ← FloatResult, GOTO[FOP2normend],	c2, at[UF2.isub, 10, FOP2end];
FOP2normend:
	TOS ← FloatResult,	c3;

FOP2Exit:
	Bank ← EmuBank,	c1;
	IBDisp, L2 ← L2.0,	c2;
	DISPNI[OpTable], L2 ← L2.0,	c3;

	S ← S + 2, CANCELBR[dataerr, 0F],	c1, at[0B, 10, illegal?];
	S ← S + 2, CANCELBR[dataerr, 0F],	c1, at[0D, 10, illegal?];
	S ← S + 2, CANCELBR[dataerr, 0F],	c1, at[0F, 10, illegal?];

dataerr:
	PC ← PC - 1, GOTO[ufnX3],	c2;

	FloatAB ← TOS LRot0, CANCELBR[$, 2],	c2, at[UF2.mult, 10, FOP2op];
	TT ← FloatA ← MD, FLTimes.A.B,	c3;

	MAR ← [rhS, S + 0],	c1;
	,	c2;
	Rx ← FloatA ← MD,	c3;

	FloatStartFlow,	c1;
	,	c2;
	,	c3;

	PC ← PC + 1,	c1;
	FloatUnloadP, Float.M,	c2;
	FloatUnloadP, Float.M,	c3;

	{Q ← PPort, }GOTO[FOPend],	c1;

	CANCELBR[ufnX3, 3],	c2, at[UF2.div, 10, FOP2op];

	FloatAB ← TOS LRot0, CANCELBR[$, 2],	c2, at[UF2.max, 10, FOP2op];
	TT ← FloatA ← MD, FLBMinusA, GOTO[FOPtail],	c3;

	FloatAB ← TOS LRot0, CANCELBR[$, 2],	c2, at[UF2.min, 10, FOP2op];
	TT ← FloatA ← MD, FLAMinusB, GOTO[FOPtail],	c3;

	Q ← FloatResult, GOTO[FOP2maxend],	c2, at[UF2.max, 10, FOP2end];
	Q ← FloatResult, GOTO[FOP2maxend],	c2, at[UF2.min, 10, FOP2end];
FOP2maxend:
	Ybus ← Q, NegBr,	c3;

	BRANCH[FOP2noswap, FOP2swap],	c1;
FOP2swap:
	TOSH ← TT,	c2;
	TOS ← Rx, GOTO[FOP2Exit],	c3;
FOP2noswap:
	,	c2;
	GOTO[FOP2Exit],	c3;

	FloatAB ← TOS LRot0, CANCELBR[$, 2],	c2, at[UF2.great, 10, FOP2op];
	TT ← FloatA ← MD, FLAMinusB, GOTO[FOPtail],	c3;
	Q ← FloatResult, GOTO[FOP2greatend],	c2, at[UF2.great, 10, FOP2end];
FOP2greatend:
	Ybus ← Q, NegBr,	c3;

	BRANCH[FOP2NIL, FOP2T],	c1;
FOP2NIL:
	TOS ← 0, GOTO[FOP2GExit],	c2;
FOP2T:
	TOS ← KTval,	c2;
FOP2GExit:
	TOSH ← 0, GOTO[FOP2Exit],	c3;

{@UNBOX1:	opcode[354'b],
	Bank ← LUBank,	c1;
	uTOS ← TOS,	c2;
	uTOSH ← TOSH, CROSS[UB1Start],	c3;
}
	at[UB1Start],
	Xbus ← ibNA, XDisp,	c1;
	DISP4[UB1fn], FloatNop,	c2;

	{unboxed to boxed}
	at[UF1.utob, 10, UB1fn],
	uNewValLo ← TOS, L1 ← L1.fixFV,	c3;

	Bank ← EmuBank,	c1;
	uNewValHi ← TOSH, L3 ← L3.utob,	c2;
	Q ← LS4FptType, CROSS[CCEntry],	c3;

	{abs of unboxed}
	at[UF1.abs, 10, UB1fn],
	Rx ← RShift1 Rx xor ~Rx, SE ← 0,	c3;

	TOSH ← TOSH and Rx,	c1;
UBSend:
	Xbus ← ib,	c2;
	PC ← PC + 1, GOTO[FOP2Exit],	c3;

	{neg of unboxed}
	at[UF1.neg, 10, UB1fn],
	Rx ← RShift1 0, SE ← 1,	c3;

	TOSH ← TOSH xor Rx, GOTO[UBSend],	c1;
 
 	{boxed to unboxed}
	at[UF1.btou, 10, UB1fn],
{	GOTO[ufnX1],	c3;}

	Ybus ← TOSH xor smallpl, ZeroBr, L2 ← L2.btou,	c3;

	Ybus ← TOSH xor smallpl, ZeroBr, BRANCH[$, btouSP],	c1;
	TT ← TOS, BRANCH[$, btouSN],	c2;
	Rx ← TOSH, GOTO[GetFPT],	c3;

	PC ← PC + 1,	c1, at[L2.btou, 10, FptGetRet];
	Xbus ← ib,	c2;
	GOTO[FOP2Exit],	c3;

	{convert small integers to floating point}
btouSP:
	CANCELBR[$],	c2;
	ufloat ← 0, GOTO[smallconv],	c3;
btouSN:
	ufloat ← S xor ~S, GOTO[smallconv],	c3;

smallconv:
	FloatMode.RN.AI.FAST, FloatFLOW,	c1;
	FloatAB ← ufloat, FLFloatA,	c2;
	FloatAB ← uTOS,	c3;

	FloatStartFlow,	c1;
	,	c2;
	,	c3;

	PC ← PC + 1,	c1;
	FloatUnloadS, Float.M,	c2;
	FloatUnloadS, Float.L,	c3;

	Xbus ← ib,	c1;
	TOSH ← FloatResult, GOTO[FOP2normend],	c2;

{	GET FLOATING POINT NUMBER 
    setup:
	argument in Rx,,TT
	TOS and TOSH saved in uTOS and uTOSH
	L2 has return value

    returns:
	TOSH,,TOS contain the floating point number
	TT contains LRot1 (TOSH)
	L0 and L1 are trashed
	Q, Rx and TT are trashed
	ufnZ if argument not a number
	will page fault if value cell not resident
	rounds up

}


GetFPT:
	MAR ← Q ← [TT, Rx + 0],	c1, at[GetFPT];{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 + 0],	c1;
	Q ← 0FF,	c2;
	Q ← MD and Q,	c3;

	Ybus ← Q xor FloatpType, ZeroBr,	c1;
	Ybus ← Q xor FixpType, ZeroBr, BRANCH[GetnonFpt, $],	c2;
	CANCELBR[$],	c3;

	Map ← [rhTT,TT], L0 ← L0.RedofptGet,	c1;
	Q ← 0FF, L1 ← L1.RestoreTosB2, 	c2;
	Rx ← rhRx ← MD, XRefBr,	c3;

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

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

FptRemap:
	CALL[RLMapFixB2],	c2;

GetnonFpt:	{non-FloatType arg}
	CANCELBR[ufnX1],	c3;
{
	Ybus ← Q xor smallpl, ZeroBr, BRANCH[$, ArgisFixp],	c3;

	Ybus ← Q xor smallneg, ZeroBr, BRANCH[$, ArgisSmallp],	c1;
	TOSH ← 0 - 1, BRANCH[ArgNotNumber, ArgisSmallneg],	c2;

ArgisFixp:
	Map ← [rhTT,TT], L0 ← L0.fxptGet, CANCELBR[$],	c1;
	L1 ← L1.tosandtosh, 	c2;
	Rx ← rhRx ← MD, XRefBr,	c3;

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

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

ArgisSmallp:
	TOSH ← 0, CANCELBR[$],	c2;
	TOS ← TT, GOTO[ChipConvSmallC1],	c3;

ArgisSmallneg:
	TOS ← TT, GOTO[ChipConvSmallC1],	c3;

{	to convert using the floating point chip set }
{	small pos and negs will be directly converted in one step using FLOAT
	Fixp numbers of less than 25 bits will be directly converted in one step using FLOAT
	Fixp numbers of more than 24 bits will have their high and low parts converted separately,
	then 16 is added to the exponent of the high part,
	and then the two numbers are added
}

ChipConvSmallC3:
	,	c3;

ChipConvSmallC1:
	{number is in TOSH,,TOS}

	  FloatMode.RN.AI.FAST, FloatULS{flow},	c1;
	  FloatA ← RRot0 TOSH, FLFloatA, GOTO[ccend],	c2;

ccend:
	  FloatA ← RRot0 TOS,	c3;

	  FloatNop,	c1;
	  Noop,	c2;
	  Noop,	c3;

	  Noop,	c1;
	  FloatUMS,	c2;
	  FloatULS,	c3;

	  TOSH ← FloatResult,	c1;
	  TOS ← FloatResult, L3Disp,	c2;
	  TT ← LRot1 TOSH, RET[FptGetRet],	c3;


ChipConvFixp:
	{number is in TOSH,,TOS}
	{test if number < 24 bits}
	  Ybus ← TOSH and uFF00, ZeroBr,	c2;
	  Q ← TOSH + 0FF + 1, BRANCH[$, ChipConvSmallC1],	c3;
	  Ybus ← Q and uFF00, ZeroBr,	c1;
	  Ybus ← TOSH, NegBr, BRANCH[$, ChipConvSmallC3],	c2;
	{if so then GOTO ChipConvSmall}
	{else begin}
	{SIGN ← 0 or -1}
	  BRANCH[pos, neg],	c3;
pos:	  uRx{SIGN} ← 0, GOTO[ChipConvLong],	c1;
neg:	  uRx{SIGN} ← Rx xor ~Rx, GOTO[ChipConvLong],	c1;
ChipConvLong:
	  FloatMode.RN.AI.FAST, FloatUMS{pipe},	c2;
	  FloatA ← uRx{SIGN}, FLFloatA,	c3;

	  FloatA ← FRot0 TOS,	c1;
	  FloatA ← FRot0 Rx, FLFloatA,	c2;
	  FloatA ← FRot0 TOSH,	c3;

	  FloatA ← 08{FloatPump}, Rx ← 08,	c1;
	  FloatA ← FRot0 Rx{FloatPump},	c2;
	  FloatA ← FRot0 Rx{FloatPump},	c3;

	  FloatA ← FRot0 Rx{FloatPump},	c1;
	  FloatA ← FRot0 Rx{FloatPump},	c2;
	  FloatA ← FRot0 Rx{FloatPump},	c3;

	  FloatUMS, Rx ← Rx LRot8,	c1;
	  FloatULS,	c2;
	  TOSH ← FloatResult, FloatUMS,	c3;

	  TOS ← FloatResult, FloatULS,	c1;
	  TT ← FloatResult,	c2;
	  Q ← FloatResult,	c3;

	  Rx ← Rx + Q,	c1;
	  FloatMode.RN.AI.FAST, FloatULS{flow},	c2;
	  FloatAB ← FRot0 Rx,	c3;

	  FloatAB ← FRot0 TT,	c1;
	  FloatA ← FRot0 TOSH, FLPlus, GOTO[ccend],	c2;
ccend:
	  FloatA ← FRot0 TOS,	c3;

	  FloatNop,	c1;
	  Noop,	c2;
	  Noop,	c3;

	  Noop,	c1;
	  FloatUMS,	c2;
	  FloatULS,	c3;

	  TOSH ← FloatResult,	c1;
	  TOS ← FloatResult, L3Disp,	c2;
	{end}
	  TT ← LRot1 TOSH, RET[FptGetRet],	c3;


ArgNotNumber:
	,	c3;

}

	{ E N D }