{
File : FTS.mc
Author : Gwan Santosa
Date : 26-Jul-85 16:48:38

This program converts an array of floating points into an array of integers

The integers are 8 bits numbers, the floating points are 32 bits numbers.
The format :
(FTS Src Dest Count)

	S - 2	Src
	S - 0	Dst
	TOS	Count

opcode[372'b], alpha byte 08.

Start:	Fetch Stack parameters
	Set up SRCEMREG (set up the address of the last entry, because we work backward)
	Set up DSTMEMREG
	Call Conversion subroutine
	Decrement Count
 	Set up SRCMEMREG
	GOTO[FSILE]

Inner Loop:

	Set up SRCMEMREG
	Set up DSTMEMREG, and check interrupt
FSILE:	Call Conversion subroutine
		
	Store Result in memory
	Decrement Count, if 0, exit at FSEX0
	Count is not 0, Set up SRCMEMREG.
	Call Conversion subroutine
	Decrement Count, back to inner loop.

FSEX0:	Done

We have to work backward, i.e. : start from the tail of the array.
After page fault we only continue to convert the rest of the array
The size of the Dst is 1/2 of Src.
In the conversion subroutine, if the number is >FF, will return FF, if <0, will return 0.

Restriction :

The calling function must make sure :

1. The count is an even number, non zero.
2. The count is not greater than the number of Src elements.
3. Src and Dst is a pointer to base address of the arrays.
4. Src is a floating point array ('FLOATP).
5. Dst is an integer array ('WORD).
	
}

Set[L0.FS.RO.00, 00];
Set[L0.FS.RO.01, 01];
Set[L0.FS.NR.0F, 0F];
Set[L1.FS.NR.0B, 0B];
Set[L0.FS.RO.02, 02];
Set[L0.FS.RO.03, 03];
Set[L0.FS.NR.0C, 0C];
Set[L1.FS.NR.0C, 0C];
Set[L2.FS.FtoS.00, 00];
Set[L2.FS.FtoS.01, 01];
Set[L2.FS.FtoS.02, 02];
Set[L2.FS.FtoS.03, 03];
Set[L3.SRCMEMREG.00, 00];
Set[L3.SRCMEMREG.01, 01];
Set[L3.SRCMEMREG.02, 02];

RegDef[rSTATUS, R, 03]; {=PV}
RegDef[rRESM, R, 06]; {=Rx}
RegDef[rRESL, R, 05]; {=PC}
RegDef[rRESLtemp,R, 04]; {=S}

RegDef[uNSrcoffset, U, 51];
RegDef[urhNSrc, U, 53];
RegDef[uNDstoffset, U, 35];
RegDef[urhNDst, U, 45];
RegDef[uNSrcoffsetReal, U, 44];
RegDef[urhNSrcReal, U, 30];
RegDef[uNDstoffsetReal, U, 59];
RegDef[urhNDstReal, U, 7];

FSBK0:	Ybus ← TOSH xor smallpl, ZeroBr,	c3, at[08, 10, FOP1Disp]; {Check if size = NIL}
	
FSBK1:	TT ← 0FF + 1, BRANCH[FSER1, $],	 	c1; {set PPort to read}
	Q ← uPPsave, L1 ← L1.FS.NR.0B,		c2;
	PPort ← Q and ~TT, CALL[SaveAllRegsB2],	c3; {Save all registers}
	
	MAR ← [rhS, S - 1],			c1, at[L1.FS.NR.0B, 10, SaveRegsB2Ret]; {Point to Dst Bitmap}
	Ybus ← TOS, ZeroBr, CANCELBR[$, 2],	c2; {Check if size = 0}		
	PV ← MD, BRANCH[$, FSER0],		c3; {PV = high word V address of Dst}
					
	MAR ← [rhS, S + 0],			c1;
	S ← S - 2,				c2;
	PC ← MD, 				c3; {PC = low word V address of Dst}	
	
	MAR ← [rhS, S - 1], 			c1; {Point to Src array}		
	FloatNop, CANCELBR[$, 2],		c2;		
	Q ← MD, 				c3; {Q = high word V address of Src}
	
	MAR ← [rhS, S + 0],			c1;
	FloatNop, 				c2;		
	TT ← MD,				c3; {TT = low word V address of Src}
	
	Rx ← TOS - 1,					c1; {Set up ORGSRCMEMREG, TOS contains COUNTS}	
	Rx ← Rx LShift1, SE ← 0,			c2; {Rx = (COUNTS - 1) X 2}		
FSBK2:	TT ← TT + Rx, CarryBr,				c3;

	uNSrcoffset ← TT, BRANCH[PRNC11, PRCR11],	c1;
	
PRCR11:	Q ← Q + 1, GOTO[FSMG55],			c2;

PRNC11:	Noop,						c2;
FSMG55:	rhTT ← Q LRot0,					c3;	
		
FSBK3:	Map ← [rhTT, TT + 0], L1 ← L1.FS.NR.0C,		c1; {Map Src address}
	urhNSrc ← Q, L0 ← L0.FS.RO.00,			c2; {Must fetch 2 words for each floating point}
	rhRx ← Rx ← MD, XRefBr,				c3;
	
	MAR ← Q ← [rhRx, TT + 0], BRANCH[FSCH0, $],	c1, at[L0.FS.RO.00, 10, NRMapFixCallerB2]; {Calculate (last -1) position}
	uNSrcoffsetReal ← Q, 				c2;
	S ← MD,  					c3;
	
	Rx ← Q, FloatMode.RZ.AI.FAST,		c1;
	Q ← rhRx, 				c2;
	urhNSrcReal ← Q, 			c3;
		 
	MAR ← Q ← [rhRx, Rx + 1],		c1;
	uFix ← S, BRANCH[$, FXFS1, 1],		c2;
FSC2:	TOSH ← MD,				c3;	
	
	TT ← TOS - 1, L2 ← L2.FS.FtoS.00,	c1;	
	TT ← TT RShift1, SE ← 0, 		c2; {TT = (COUNTS - 1)/2}	
	TT ← TT + PC, CarryBr,			c3;
	
	uNDstoffset ← TT, BRANCH[DNC1, DC1],	c1;
	
DNC1:	Noop, GOTO[DSTM1],			c2;

DC1:	PV ← PV + 1,				c2;

DSTM1:	rhTT ← PV LRot0,			c3;
			
MDST:	Map ← [rhTT, TT + 0], L1 ← L1.FS.NR.0C,	c1; {Map address of Last Dst}
	urhNDst ← PV, L0 ← L0.FS.NR.0F, 	c2; {mode must be RZ for FLFixA}
	rhRx ← Rx ← MD, XwdDisp,		c3;
	
	MAR ← Q ← [rhRx, TT + 0], DISP2[FSCH1],	c1, at[L0.FS.NR.0F, 10, NRWMapFixCallerB2];
	uNDstoffsetReal ← Q,			c2, at[1, 4, FSCH1];
	Rx ← rhRx, CALL[FtoS],			c3;	 
	
	rRESLtemp ← rRESL,  			c2, at[L2.FS.FtoS.00, 10, FtoSRet];
	urhNDstReal ← Rx, L2 ← L2.FS.FtoS.02,	c3; {Save result in rRESLtemp}
		
	TOS ← TOS - 1, L3 ← L3.SRCMEMREG.00,	c1;
	Rx ← uNSrcoffsetReal, CALL[SRCMEMREG],	c2; {Set up floating point number}
	rhRx ← 	urhNDstReal, CALL[FtoS],	c3, at[L3.SRCMEMREG.00, 10, SRCMEMREGRet];	

FSIL:	L2 ← L2.FS.FtoS.02, CALL[DSTMEMREG],	c1; {Inner loop}	
	Rx ← uNSrcoffsetReal, CALL[SRCMEMREG],	c2, at[L3.SRCMEMREG.01, 10, DSTMEMREGRet];
	rhRx ← 	urhNDstReal, CALL[FtoS],	c3, at[L3.SRCMEMREG.01, 10, SRCMEMREGRet];	
	
FSILE:	rRESL ← rRESL LRot8,				c2, at[L2.FS.FtoS.02, 10, FtoSRet];
	Rx ← uNDstoffsetReal, L2 ← L2.FS.FtoS.03,	c3;	
		
	MAR ← [rhRx, Rx + 0], L3 ← L3.SRCMEMREG.02,	c1; {Store in Dst}
	MDR ← rRESLtemp or rRESL,			c2; {Compact the result}
	TOS ← TOS - 1, ZeroBr,				c3; {Decrement counter}
	
	uTOS ← TOS, BRANCH[$, FSEX0],		c1; {uTOS is updated every 2 counts}
	Rx ← uNSrcoffsetReal, CALL[SRCMEMREG],	c2;
	CALL[FtoS],				c3, at[L3.SRCMEMREG.02, 10, SRCMEMREGRet];
	
	TOS ← TOS - 1, L3 ← L3.SRCMEMREG.01,	c2, at[L2.FS.FtoS.03, 10, FtoSRet];
	rRESLtemp ← rRESL, GOTO[FSIL],		c3;

{
========================================================================
Conversion
========================================================================
}
	
FtoS:	FloatAB ← uFix, FLFixA,	c1;	
	FloatAB ← TOSH LRot0,	c2;	
	FloatStartFlow,		c3;
		
	uRx ← Rx,		c1;	
	Noop,			c2;
	Noop,			c3;
	
	Noop,			c1;	
	FloatUnloadS, Float.M,	c2; {unload MS word}
	FloatUnloadS, Float.L,	c3; {unload LS word}
	
	rSTATUS ← PPort,	c1; {store MS word of result}
	rRESM ← FloatResult, 	c2; {read status}
	rRESL ← FloatResult, 	c3; {LS word}	
	
	Xbus ← rRESM LRot8, XDisp,			c1; {Check sign bit}
	Ybus ← rRESM, ZeroBr, DISP4[FSRSF, 0E], 	c2; {If 0, check further}
					  		    {If 1, force low word to 0}
							    
	rRESL ← 0, CANCELBR[$],	L2Disp,	c3, at[0F, 10, FSRSF];
		
FSOK2:	Rx ← uRx, RET[FtoSRet],		c1;								    
								   
	Rx ← uRx, BRANCH[FSLF0, FSMG0],	c3, at[0E, 10, FSRSF];

FSLF0:	rRESL ← 0FF, 			c1; {Force low word to 0FF}
	Noop,				c2;
	L2Disp,	GOTO[FSOK2],		c3;	
	
FSMG0:	TT ← rRESL and ~0FF,		c1;
	Ybus ← TT, ZeroBr, 		c2;	
	BRANCH[FC255, FSOK1], L2Disp,	c3;
	
FC255:	rRESL ← 0FF, RET[FtoSRet], 	c1; {Force low word to 0FF}
	
FSOK1:	RET[FtoSRet],			c1;

{
========================================================================
DSTMEMREG
========================================================================
}

DSTMEMREG:

	rhRx ← 	urhNDstReal,			c2;
	Rx ← uNDstoffsetReal, MesaIntBr,	c3; {Check interrupts}
	
	Ybus ← uWDC, NZeroBr, BRANCH[FTSNI1, $],	c1;
	Ybus ← uWP, ZeroBr, BRANCH[FTSI1, FTSNI2],	c2;

FTSNI1:	CANCELBR[$],				c2;
FTSNI2:	CANCELBR[FTSNI3],			c3;

FTSI1:	uWP ← 0, BRANCH[FTSIN, $],		c3;
		
FTSNI3:	MAR ← Rx ← [rhRx, Rx - 1],	c1; {Set up Dst address}
	TOSH ← Rx, BRANCH[$, FSFX0, 1],	c2;	
DSMG3:	Q ← rhRx,			c3;

	urhNDstReal ← Q,		c1; {The real address of Dst is decremented by 2 each time}
	uNDstoffsetReal ← Rx, 		c2;	
	L3Disp,				c3;
	
	RET[DSTMEMREGRet],		c1;
			
{
========================================================================
SRCMEMREG
========================================================================

This subroutine fetch 32 bits floating point number
}

SRCMEMREG:
		
	rhRx ← urhNSrcReal,		c3;
		
	MAR ← Rx ← [rhRx, Rx - 1],	c1;
	TOSH ← Rx, BRANCH[$, FSFX1, 1],	c2;
SRCT1:	TOSH ← MD,			c3;
	
	MAR ← Rx ← [rhRx, Rx - 1],	c1;
	Q ← Rx, BRANCH[$, FSFX2, 1],	c2;
SRCT2:	Q ← MD,				c3;

	uFix ← Q,			c1;
	Q ← rhRx,			c2;
	urhNSrcReal ← Q,		c3; {Update the real address}
			
	uNSrcoffsetReal ← Rx, L3Disp,	c1; {The real address of Src is decremented by 2 each time}
	RET[SRCMEMREGRet],		c2;
	
{
================================================================================================
Error cases
================================================================================================
}

FSER0:	PV ← uPVx,		c1;

FSER1:	GOTO[ufnX3],		c2;
			
{
================================================================================================
Exit points
================================================================================================
}

FSEX0:	TOSH ← smallpl,					c2;
	Q ← 4'd, 					c3;

	Xbus ← ib, GOTO[RestoreAllRegsAndExitB2],	c1;

{
========================================================================
Remap
========================================================================
}

FSCH0:	CALL[NRLMapFixB2],			c2;
	
FXFS1:	TT ← uNSrcoffset,			c3;
	
	Rx ← 0FF + 1,				c1;
	TT ← TT + Rx, CarryBr,			c2;
	Rx ← urhNSrc, BRANCH[SNC1, SC1],	c3;
	 
SNC1:	Noop, GOTO[SRMG1],	c1;

SC1:	Rx ← Rx + 1,		c1;

SRMG1:	rhTT ← Rx LRot0,	c2;
	L0 ← L0.FS.RO.01,	c3;
	
	Map ← [rhTT, TT + 0], 	c1;
	L1 ← L1.FS.NR.0C,	c2;
	rhRx ← Rx ← MD, XRefBr,	c3;
	
	MAR ← [rhRx, Q + 0], BRANCH[FSCH3, $],	c1, at[L0.FS.RO.01, 10, NRMapFixCallerB2];
	GOTO[FSC2],				c2;

FSCH3:	CALL[NRLMapFixB2],			c2;

FSFX0:	TT ← uNDstoffset,			c3;
	
	Q ← 0FF + 1,				c1;
	
	TT ← TT - Q, CarryBr,			c2;
	Q ← urhNDst, BRANCH[SBR2, SNBR2],	c3;
	
SNBR2:	Noop, GOTO[SMG03],			c1;

SBR2:	Q ← Q - 1,				c1;

SMG03:	rhTT ← Q LRot0,				c2;
	urhNDst ← Q, L1 ← L1.FS.NR.0C,		c3;	
		
	Map ← [rhTT, TT + 0],			c1;
	uNDstoffset ← TT, L0 ← L0.FS.NR.0C,	c2;
	rhRx ← Rx ← MD, XwdDisp,		c3;
	
	MAR ← Q ← [rhRx, TOSH + 0], DISP2[FSCH6],	c1, at[L0.FS.NR.0C, 10, NRWMapFixCallerB2];
	Rx ← Q, GOTO[DSMG3],				c2, at[1, 4, FSCH6];

FSFX1:	TT ← uNSrcoffset,			c3;

	Q ← 0FF + 1,				c1;	
	TT ← TT - Q, CarryBr,			c2;
	Q ← urhNSrc, BRANCH[SBR1, SNBR1],	c3;
	
SNBR1:	Noop, GOTO[SMG02],		c1;

SBR1:	Q ← Q - 1,			c1;

SMG02:	rhTT ← Q LRot0,			c2;
	urhNSrc ← Q, L0 ← L0.FS.RO.02,	c3;
			
	Map ← [rhTT, TT + 0],			c1;
	uNSrcoffset ← TT, L1 ← L1.FS.NR.0C,	c2;
	rhRx ← Rx ← MD, XRefBr,			c3;
	
	MAR ← Q ← [rhRx, TOSH + 0], BRANCH[FSCH66, $],	c1, at[L0.FS.RO.02, 10, NRMapFixCallerB2];
	Rx ← Q, GOTO[SRCT1],				c2;				

FSCH66:	CALL[NRLMapFixB2],			c2;
		
FSFX2:	TT ← uNSrcoffset,			c3;

	Rx ← 0FF + 1,				c1;	
	TT ← TT - Rx, CarryBr,			c2;
	Rx ← urhNSrc, BRANCH[SBR3, SNBR3],	c3;
	
SNBR3:	Noop, GOTO[SMG02],		c1;

SBR3:	Rx ← Rx - 1,			c1;

SMG04:	rhTT ← Rx LRot0,		c2;
	urhNSrc ← Rx, L0 ← L0.FS.RO.03,	c3;	
		
	Map ← [rhTT, TT + 0],			c1;
	uNSrcoffset ← TT, L1 ← L1.FS.NR.0C,	c2;
	rhRx ← Rx ← MD, XRefBr,			c3;
	
	MAR ← Q ← [rhRx, Q + 0], BRANCH[FSCH7, $],	c1, at[L0.FS.RO.03, 10, NRMapFixCallerB2];
	Rx ← Q, GOTO[SRCT2],				c2;
		
FSCH7:	CALL[NRLMapFixB2],				c2;	
	
	GOTO[NRWLMapFixB2],	c2, at[0, 4, FSCH6];
	GOTO[NRWLMapFixB2],	c2, at[2, 4, FSCH6];
	GOTO[NRWLMapFixB2],	c2, at[3, 4, FSCH6];

	GOTO[NRWLMapFixB2],	c2, at[0, 4, FSCH1];
	GOTO[NRWLMapFixB2],	c2, at[2, 4, FSCH1];
	GOTO[NRWLMapFixB2],	c2, at[3, 4, FSCH1];
	
	Q ← 0, GOTO[RestoreAllRegsAndPFB2],	c1, at[L1.FS.NR.0C, 10, NTrapFixesB2];

{
==============================================================================================
Handle Interrupts
==============================================================================================
}

FTSIN:	TOS ← uTOS,		c1;
	TOSH ← uTOSH,		c2;
	S ← uS,			c3;	
		
FTGIN:	Bank ← EmuBank,			c1;
	PV ← uPVx,			c2;
	PC ← uPC, CROSS[EmuInt],	c3;

				
	{END}