{******************************************************************}
{*****************  FLOYD ALGORITHM SUBROUTINES   *****************}
{******************************************************************}
{ File:          FloydSubs.mc
  Create by:     Martin J. Shramo, June 1986
  Last Edited:   19-Dec-86 13:46:54
}

{ to list use: print gacha8/f /-a FloydSubs.mc  }

	
{******************************************************************

	fSaveState  SUBROUTINE (Saves the state of the instruction for interrupt or
			       page fault handling)
	first Cycle = c2, last cycle = c3
	
This routine save the current state of the instruction on the stack.  Only the following state variables need to be updated:  uSTKMisc, uInPtrVL, uOutPtrVL, uErrPtrVL and uErrPtrVH. The rest of the state variables are updated as they are changed.
  
	CALLING ARGUMENTS
	
L0		caller			
uRtnReason	interrupt or page fault flag	(UA4)
uByte		byte of pixel pair being used	(UA1)
uPolarity 	invert flag			(UA0)
rSrcLow		gray input real low address pointer	(R03)
rDstLow		output real low address pointer		(R04)
rErrLow		error buffer real low address pointer	(R05)

	ALWAYS UPDATES

uSTKMisc	misc data for interrupt/page fault returns	(U0F)
uInPtrVL	gray input low virtual address pointer		(U06)
uOutPtrVL	output low virtual address pointer		(U08)
uErrorPtrVL	error buffer low virtual address pointer	(U0A)	
uErrorPtrVH	error buffer high virtual address pointer	(U09)
	
	USES
	
rTT		temp register		(R06)
rTT2		temp register		(R00)
rTT3		temp register		(R09)
rTT4		temp register		(R0B)

	RETURNS THROUGH	
	
fSaveStateRet

}

fSaveState:
{ update uSTKMisc }
	rTT ← uByte LShift1,SE ← 0		,c2;
	rTT2 ← uPolarity			,c3;
	rTT ← rTT or rTT2			,c1;
	rTT2 ← uRtnReason			,c2;
	uSTKMisc ← rTT or rTT2			,c3;
	rTT2 ← rTT2 + 0,ZeroBr			,c1;
	pRet0,BRANCH[$,fNoUpdateVPs]		,c2;{0:PFReturn, ~0:INTReturn}
{ update the virtual pointers }
	rTT ← rSrcLow and 0FF,CANCELBR[$,0F]	,c3;{source virt addr}
	rTT2 ← uInPtrVL				,c1;
	rTT2 ← rTT2 and ~0FF			,c2;
	uInPtrVL ← rTT2 or rTT			,c3;
	
	rTT ← rDstLow and 0FF			,c1;{dest virt addr}
	rTT2 ← uOutPtrVL			,c2;
	rTT2 ← rTT2 and ~0FF			,c3;
	uOutPtrVL ← rTT2 or rTT			,c1;
	
	rTT ← rErrLow and 0FF			,c2;{error virt addr}
	rTT2 ← uErrorPtrVL			,c3;
	rTT2 ← rTT2 and ~0FF			,c1;
	rTT2 ← rTT2 or rTT			,c2;
	rTT2 ← rTT2 - 1,CarryBr			,c3; {get the error buff addr to write to}
	uErrorPtrVL ← rTT2,BRANCH[$,fRHVaddrOK]	,c1;
	{ need to decr RH virt addr }
	rTT ← uErrorPtrVH			,c2;
	rTT ← rTT - 1				,c3;
	uErrorPtrVH ← rTT			,c1;
fRHVaddrOK: { the RH virt addr does not need to be decr. }
	pRet0					,c2;
fNoUpdateVPs: { no update of the virtual pointers }
	RET[fSaveStateRet]			,c3;
	
	
	
{******************************************************************

	fGetState  SUBROUTINE (Gets the state of the instruction after interrupt or
			       page fault handling)
	first Cycle = c1, last cycle = c3
	
This routine retrieves the current state of the instruction from the stack.  The state variables that are retrieved are uByte, uRtnReason, uPolarity, uThreshold, and uMaxValue.  Three of these values are incoded into uSTKMisc, two into uThreshAndMax. The rest of the state variables are used from the stack.
  
	CALLING ARGUMENTS

uThreshAndMax	threshold and max value				(U03)
uSTKMisc	misc data for interrupt/page fault returns	(U0F)
	
	ALWAYS UPDATES
	
uPolarity	invert flag			(UE0)
uByte		byte of pixel pair being used	(UE1)
uRtnReason	interrupt or page fault flag	(UE2)
uThreshold	threshold value			(UE3)
uMaxValue	max pixel value			(UE4)

	USES
    
rTT   	temp register		(R06)
	
	RETURNS TO
	
fGetStateRet		
}

fGetState:
	Xbus ← uSTKMisc,XDisp			,c1;
	rTT ← 1,BRANCH[fNoInvert,fYesInvert,0E]	,c2; {used as constant}
fNoInvert:
	uPolarity ← 0,GOTO[fSetPolarityDone]	,c3;
fYesInvert:
	uPolarity ← rTT				,c3;
fSetPolarityDone:
	Xbus ← uSTKMisc,XDisp			,c1;
	BRANCH[fZeroByte,fOneByte,0D]		,c2;
fZeroByte:
	uByte ← 0,GOTO[fSetByteDone]		,c3;
fOneByte:
	uByte ← rTT				,c3;
fSetByteDone:
	Xbus ← uSTKMisc,XDisp			,c1;
	rTT ← INTRtn,BRANCH[fPFrtn,fINTrtn,0B]	,c2;
fPFrtn:
	uRtnReason ← PFRtn,GOTO[fGetThreshAndMax],c3;
fINTrtn:
	uRtnReason ← rTT			,c3;
fGetThreshAndMax:
	rTT ← uThreshAndMax			,c1;
	Q ← rTT and 0FF				,c2;
	uMaxValue ← Q				,c3;
	rTT ← rTT LRot8				,c1;
	rTT ← rTT and 0FF			,c2;
	uThreshold ← rTT, GOTO[fGetStateRet]	,c3;

{******************************************************************

	fGetAllPages  SUBROUTINE (Gets all pages into real memory)
	first Cycle = c3, last cycle = c2
	
This routine pulls all source, destination and error buffer pages into real memory.  The R register pointers for the real addresses are updated.  The includes the locations that are read and the locations that are written in the error buffer.  If a page fault occurs, code is transferred to that will save the state of the instruction and goto the page fault handler.
  
	CALLING ARGUMENTS
uCount		number of input pixels (U02)
uInPtrVH	source data virt address (U05)	
uInPtrVL	source data virt address (U06)
uOutPtrVH	destination data virt address (U07)
uOutPtrVL	destination data virt address (U08)
uErrorPtrVH	error data virt address (U09)
uErrorPtrVL	error data virt address (U0A)
uBit		Bit-address of output pixel (U0B)
L2		caller	   

	ALWAYS UPDATES
rSrcLow		source real address (R03)
rhSrcHi		source real address (RH03)
rDstLow		destination real address (R04)
rhDstHi		destination real address (RH04)
rErrLow		write error real address (R05)
rhErrHi		write error real address (RH05)
rOldErrorLow	read error real address (R07)
rhOldErrorHi	read error real address (RH07)

	USES
rTT		temp (R06)
rTT3		temp (R09)
rTT4		temp (R0B)
Q		temp
rDstReal	interface to MapGrDst (R06)
rhDstReal	interface to MapGrDst (RH06)
rVirtualL		interface to MapGrDst (R0B)
rhVirtualH 	interface to MapGrDst (RH06)
bitWidth	interface to ComMap (R02)
byteWidth	interface to ComMap (R02)
wordWidth	interface to ComMap (R02)
DBit		interface to ComMap (R09)
DByte		interface to ComMap (R09)
VD		interface to ComMap (R01)
rhVD		interface to ComMap (RH01)
BARealALo	interface to ComMap (R0C)
BARealAHi	interface to ComMap (RH0C)
L0		interface to MapGrDst
L1		interface to ComMap
L3		interface to ComMap

Q		used by ComMap
Regb		used by ComMap (R0B)
Reg6		used by ComMap (R06)
Reg0		used by ComMap (R00)
rhRegD		used by ComMap (RH0D)
Rege		used by ComMap (RH0E)

	RETURNS THROUGH
fGetAllPagesRet	Success case, via L2
fScrFlt		source page fault, via GOTO
fDstFlt		destination page fault, via GOTO
fErrFlt		error page fault, via GOTO 

}

fGetAllPages:


{ Source Data case }
	VD ← uInPtrVL,L3 ← L3.FloydSrc	,c3;{return for ComMap}
	rhVD ← uInPtrVH			,c1; 
	DByte ← uByte,L1 ← 0		,c2; {want to look at src case}
	byteWidth ← uCount,CALL[ComMapByte] ,c3;
	
	{ save real address }
	rSrcLow ← BARealALo,BRANCH[$,fSrcFlt] ,c2,at[L3.FloydSrc,10,ComMapRet];
	Q ← BARealAHi			,c3;
	rhSrcHi ← Q LRot0		,c1;
	
{ Destination Data case}
	bitWidth ← uCount,L3 ← L3.FloydDst ,c2; {return for ComMap}
	VD ← uOutPtrVL			,c3;
	rhVD ← uOutPtrVH  		,c1; 
	DBit ← uBit,L1 ← 1		,c2; {want to look at dst case}
	CALL[ComMap]			,c3;
	
	{ save real addresses }
	rDstLow ← BARealALo,BRANCH[$,fDstFlt] ,c2,at[L3.FloydDst,10,ComMapRet];
	Q ← BARealAHi,L1 ← 1		,c3; {want to look at dst case}
	rhDstHi ← Q LRot0		,c1; 
	
{ Error Data Case }
	VD ← uErrorPtrVL,L3 ← L3.FloydErrBuf ,c2; {return for ComMap}
	rhVD ← uErrorPtrVH		,c3; 
	wordWidth ← uCount		,c1;
	wordWidth ← wordWidth + 1	,c2; {error buffer is 1 longer than others}
	CALL[ComMapWord]		,c3;
	
	{ save real addresses }
	rOldErrorLow ← BARealALo,BRANCH[$,fErrFlt] ,c2,at[L3.FloydErrBuf,10,ComMapRet];
	Q ← BARealAHi			,c3; { error buff address to write to }
	rhOldErrorHi ← Q LRot0		,c1;
	
{ get the error buffer address to read from }
	rErrLow ← BARealALo + 1,PgCarryBr ,c2;
	rVirtualL ← uErrorPtrVL,BRANCH[fErrNoCarry,$] ,c3;
{ we have a page cross on the error address, update the virt. address }
	rTT3 ← 0FF + 1,L0 ← L0.FloydErrBuf ,c1;{return for MapDst}
	rVirtualL ← rVirtualL and ~(0FF)	,c2;
	rVirtualL ← rVirtualL + rTT3,CarryBr,c3;
	uErrorPtrVL ← rVirtualL,BRANCH[fErrNoTopCarry,$] ,c1;
{ need to carry into the rh register }
	Q ← uErrorPtrVH			,c2;
	Q ← Q + 1			,c3;
	uErrorPtrVH ← Q			,c1;
fErrNoTopCarry:
	rhVirtualH ← uErrorPtrVH		,c2;
	CALL[MapDst]			,c3; 
	
{ can't get a page fault, already checked pages }
	rErrLow ← rDstReal		,c3,MapDstRet[L0.FloydErrBuf];
	Q ← rhDstReal,pRet2,GOTO[fGetDone] ,c1;
	
fErrNoCarry:
	Q ← BARealAHi,pRet2		,c1;
fGetDone:
	rhErrHi ← Q LRot0,RET[fGetAllPagesRet] ,c2;
	
	
 {******************************************************************

	fSaveRegs  SUBROUTINE (Save system registers before Floyd uses them.)
	first Cycle = c2, last cycle = c1
	
This subroutine is used to save system regs in U. Note that the caller MUST save L before calling.
  
	CALLING ARGUMENTS
	L2	caller   

	ALWAYS UPDATES
	
	G	->	UGsave
	rhG	->	UrhGsave
	PC	->	UPCsave
	rhPC	->	UrhPCsave
	L	->	UrhLsave
	rhL	->	UrhLsave

	USES


	RETURNS THROUGH
 
	fSaveRegsRet
}

fSaveRegs:	
	L ← rhL					,c2, at[0,10,fSaveRegs];
	UPCsave ← PC				,c3;
	UGsave ← G				,c1;

	{the following Uregs are at "xB" to allow "← rh"}
	UrhLsave ← L, G ← rhG 			,c2;
	UrhGsave ← G, PC ← rhPC, pRet2		,c3;
	UrhPCsave ← PC, RET[fSaveRegsRet],	,c1;



{******************************************************************

	fRestoreRegs  SUBROUTINE (Restore system registers after Floyd uses them.)
	first Cycle = c1, last cycle = c1
	
This subroutine is used to restore system regs from U.
  
	CALLING ARGUMENTS
	L0	caller   

	ALWAYS UPDATES
	
	r0100	←	0FF + 1
	G	←	UGsave
	rhG	←	UrhGsave
	PC	←	UPCsave
	rhPC	←	UrhPCsave
	L	←	UrhLsave
	rhL	←	UrhLsave

	USES


	RETURNS THROUGH
 
	fRestoreRegsRet
}
fRestoreRegs:
	rhL ← UrhLsave			,c1,at[1,10,fSaveStateRet];
	rhPC ← UrhPCsave		,c2;
	rhG ← UrhGsave			,c3;
	PC ← UPCsave			,c1;
	r0100 ← 0FF + 1			,c2;
	G ← UGsave,pRet0		,c3;
	L ← ULsave, RET[fRestoreRegsRet] ,c1;