{File name:  GrayBltSubs.mc
Description: Common subroutines for Bank1 opcodes.
Author: JPM
Created: May 29, 1986
Last Revised:
October 14, 1986 -- JPM -- add comments
August 7, 1986 -- JPM -- generalize subroutine & register names (e.g. MapSrc instead of MapGrSrc)
August 5, 1986 -- JPM -- set stackP in LoadGTable
July 17, 1986 -- JPM -- rename Incr/DecrVA to BumpByteVA/BumpByteVANeg
July 14, 1986 -- JPM -- change meaning of rTemp parameter to LoadGTable, add label LoadGTableSideDoor
July 11, 1986 -- JPM -- remove GMFFault (now in Bank1Misc.mc and renamed Bank1Fault)
July 10, 1986 -- JPM -- fix bug in MapGrDest (must mask extraneous XWtOKDisp bits); invert rTemp return from Incr/DecrVA; add forced branch to returns from map fix
June 26, 1986 -- JPM -- add IncrVA and DecrVA; redo MapGrSrc and MapGrDest
June 13, 1986 -- JPM -- use new register names
June 12, 1986 -- JPM -- fix LRotateN to do L0Disp before dispatching on RMaskNNNN; change MapGrSrc and MapGrDest to use rh/r regs instead of u regs}

{	Copyright (C) 1986 by Xerox Corporation.  All rights reserved.}

{LoadTable: for loading any 16-word-aligned table into stack regs}
{Parameters:
	[rhVirtualH, rVirtualL] contains virtual address of last word of table
	rTemp contains table size minus 1 (incremented by 2 for last U-reg index)
Scratch regs:
	[rhSrcReal, rSrcReal] used for real address of table words
	rCount and Q used for interim storage of data
	L1 used for map fix call
Initial condition:
	Map started in cycle 1 on virtual page
Return:
	L0 used for return from subroutine}

LoadTable:
	rTemp ← rTemp + 2, L1 ← 0, push,				c2;
LoadTableSideDoor:
	rhSrcReal ← rSrcReal ← MD, XRefBr,				c3;

LTa:	MAR ← Q ← [rhSrcReal, rVirtualL + 0], BRANCH[TableFix,$,2],	c1, at[0,10,MFRtn];
	rSrcReal ← Q, stackP ← rTemp,					c2;
	rCount ← MD,							c3;

LTLoop:
	MAR ← rSrcReal ← [rhSrcReal, rSrcReal - 1], NibCarryBr,		c1;
	Ybus ← rTemp, AltUaddr, rTemp ← rTemp - 1, L0Disp, BRANCH[LTEnd,$,2], c2;
	uyStack ← rCount, rCount ← MD, CANCELBR[LTLoop,0F],		c3;
LTEnd:	uyStack ← rCount, DISP4[LoadTableRtn],				c3;

TableFix:
	CALL[MapReadFix],						c2;

{fault return from MapReadFix comes here}
	uFaultParm1 ← Q, CANCELBR[Bank1Fault,0F],			c2, at[0,10,MFFaultRtn];

{MapSrc: map source virtual page to real, check flags}
{Parameters:
	[rhVirtualH, rVirtualL] contains virtual address of source
Scratch regs:
	Q used for interim storage of data
Return:
	[rhSrcReal, rSrcReal] loaded with real address of source
	L0 used for return from subroutine}

MapSrc:
	Map ← [rhVirtualH, rVirtualL],					c1;
	L1 ← 1,								c2;
	rhSrcReal ← rSrcReal ← MD, XRefBr,				c3;

	MAR ← Q ← [rhSrcReal, rVirtualL + 0], L0Disp, BRANCH[MSFix,$,2], c1, at[1,10,MFRtn];
	rSrcReal ← Q, RET[MapSrcRtn],					c2;

MSFix:
	CANCELBR[MapReadFix,0F],					c2;

{fault return from MapReadFix comes here}
	uFaultParm1 ← Q, RET[MapSrcFault],				c2, at[1,10,MFFaultRtn];

{MapDst: map destination virtual page to real, check flags}
{Parameters:
	[rhVirtualH, rVirtualL] contains virtual address of destination
Scratch regs:
	Q used for interim storage of data
Return:
	[rhDstReal, rDstReal] loaded with real address of destination
	L0 used for return from subroutine}

MapDst:
	Map ← [rhVirtualH, rVirtualL],					c1;
	L1 ← 2,								c2;
	rhDstReal ← rDstReal ← MD, XWtOKDisp,				c3;

	MAR ← Q ← [rhDstReal, rVirtualL + 0], L0Disp, BRANCH[MDFix,$,0D], c1, at[2,10,MFRtn];
	rDstReal ← Q, RET[MapDstRtn],					c2;

MDFix:
	CANCELBR[MapWriteFix,0F],					c2;

{fault return from MapWriteFix comes here}
	uFaultParm1 ← Q, RET[MapDstFault],				c2, at[2,10,MFFaultRtn];

MapReadFix:
	Xbus ← rSrcReal LRot0, XwdDisp,					c3;

	Map ← [rhVirtualH, rVirtualL], DISP2[MFRa],			c1;
MFRa:	MDR ← rSrcReal or map.referenced, L1Disp, GOTO[MFb],		c2, at[0,4];
	MDR ← rSrcReal or map.referenced, L1Disp, GOTO[MFb],		c2, at[1,4,MFRa];
	MDR ← rSrcReal or map.referenced, L1Disp, GOTO[MFb],		c2, at[2,4,MFRa];
	T ← qPageFault, GOTO[MFc],					c2, at[3,4,MFRa];
MFb:	Xbus ← 3, XDisp, RET[MFRtn],					c3;
MFc:	uFaultParm0 ← rVirtualL, L1Disp,				c3;

	Q ← rhVirtualH, L0Disp, RET[MFFaultRtn],			c1;

MapWriteFix:
	Xbus ← rDstReal LRot0, XwdDisp,					c3;

	Map ← [rhVirtualH, rVirtualL], DISP2[MFWa],			c1;
MFWa:	MDR ← rDstReal or map.rd, L1Disp, GOTO[MFb],			c2, at[0,4];
	T ← qWriteProtect, GOTO[MFc],					c2, at[1,4,MFWa];
	MDR ← rDstReal or map.rd, L1Disp, GOTO[MFb],			c2, at[2,4,MFWa];
	T ← qPageFault, GOTO[MFc],					c2, at[3,4,MFWa];

{BumpByteVA: Increment virtual byte address}
{BumpByteVANeg: Decrement virtual byte address}
{Parameters:
	[rhVirtualH, rVirtualL] contains virtual word address
	rTemp contains byte increment or decrement (branch to BumpByteVA if positive, BumpByteVANeg if negative)
Execution:
	5 cycles starting from anywhere
Return:
	[rhVirtualH, rVirtualL] updated to new word address
	Q also has contents of rhVirtualH
	rTemp contains inverted byte offset
	L1 used for return from subroutine}

BumpByteVA:
	rTemp ← DRShift1 rTemp, SE ← 0, GOTO[IncrDecrVA],		c*;
BumpByteVANeg:
	rTemp ← DRShift1 rTemp, SE ← 1, NegBr,				c*;
IncrDecrVA:
	rVirtualL ← rVirtualL + rTemp, CarryBr, BRANCH[IncrVAChkCarry,DecrVAChkCarry], c*;
IncrVAChkCarry:
	rTemp ← DLShift1 ~rTemp xor rTemp, BRANCH[IncrVANoCarry,IncrVACarry], c*;
DecrVAChkCarry:
	rTemp ← DLShift1 ~rTemp xor rTemp, BRANCH[DecrVANoCarry,DecrVACarry], c*;

IncrVANoCarry:
	Q ← rhVirtualH, L1Disp, GOTO[BumpByteVAEnd],			c*;
IncrVACarry:
	Q ← rhVirtualH + 1, LOOPHOLE[byteTiming], L1Disp, GOTO[BumpByteVAEnd], c*;
DecrVANoCarry:
	Q ← rhVirtualH - 1, LOOPHOLE[byteTiming], L1Disp, GOTO[BumpByteVAEnd], c*;
DecrVACarry:
	Q ← rhVirtualH, L1Disp, GOTO[BumpByteVAEnd],			c*;
BumpByteVAEnd:
	rhVirtualH ← Q LRot0, RET[BumpByteVARtn],			c*;

{LRotateN: does LRotN, and also creates an N-bit right-justified mask}
{Parameters:
	Q contains data
	rhTemp contains N (1 - 10H)
Execution:
	5 cycles starting from anywhere
Return:
	rTemp contains rotated data
	rMaskN contains N-bit right-justified mask
	L0 used for return from subroutine}

LRotateN:
	rTemp ← LRot1 Q, Xbus ← rhTemp, XDisp,			  c*;
	rTemp ← LRot1 rTemp, Xbus ← rhTemp, XDisp, DISP4[LRotXXNN,0C], c*;
	rTemp ← Q, Xbus ← rhTemp, XDisp, DISP4[LRotNNXX,3],	  c*, at[0C,10,LRotXXNN];
	rTemp ← LRot1 Q, Xbus ← rhTemp, XDisp, DISP4[LRotNNXX,3], c*, at[0D,10,LRotXXNN];
	rTemp ← rTemp, Xbus ← rhTemp, XDisp, DISP4[LRotNNXX,3],	  c*, at[0E,10,LRotXXNN];
	rTemp ← LRot1 rTemp, Xbus ← rhTemp, XDisp, DISP4[LRotNNXX,3], c*, at[0F,10,LRotXXNN];
	rTemp ← rTemp LRot0, L0Disp, DISP4[RMaskNNNN],		  c*, at[3,10,LRotNNXX];
	rTemp ← rTemp LRot4, L0Disp, DISP4[RMaskNNNN],		  c*, at[7,10,LRotNNXX];
	rTemp ← rTemp LRot8, L0Disp, DISP4[RMaskNNNN],		  c*, at[0B,10,LRotNNXX];
	rTemp ← rTemp LRot12, L0Disp, DISP4[RMaskNNNN],		  c*, at[0F,10,LRotNNXX];

{RMaskN: creates an N-bit right-justified mask}
{Parameters:
	rhTemp contains N (1 - 10H)
Execution:
	3 cycles starting from anywhere
Return:
	rMaskN contains mask
	L0 used for return from subroutine}

RMaskN:
	Xbus ← rhTemp, XDisp,					  c*;
	L0Disp, DISP4[RMaskNNNN],{note that 10H causes a 0 disp}  c*;
	rMaskN ← 1, RET[RMaskNRtn],				  c*, at[1,10,RMaskNNNN];
	rMaskN ← 3, RET[RMaskNRtn],				  c*, at[2,10,RMaskNNNN];
	rMaskN ← 7, RET[RMaskNRtn],				  c*, at[3,10,RMaskNNNN];
	rMaskN ← 0F, RET[RMaskNRtn],				  c*, at[4,10,RMaskNNNN];
	rMaskN ← 1F, RET[RMaskNRtn],				  c*, at[5,10,RMaskNNNN];
	rMaskN ← 3F, RET[RMaskNRtn],				  c*, at[6,10,RMaskNNNN];
	rMaskN ← 7F, RET[RMaskNRtn],				  c*, at[7,10,RMaskNNNN];
	rMaskN ← 0FF, RET[RMaskNRtn],				  c*, at[8,10,RMaskNNNN];
	rMaskN ← LShift1 0FF, SE←1, RET[RMaskNRtn] {rMaskN ← 1FF}, c*, at[9,10,RMaskNNNN];
	rMaskN ← RShift1 u7FF, RET[RMaskNRtn] {rMaskN ← 3FF},	  c*, at[0A,10,RMaskNNNN];
	rMaskN ← u7FF, RET[RMaskNRtn] {rMaskN ← 7FF},		  c*, at[0B,10,RMaskNNNN];
	rMaskN ← RShift1 u1FFF, RET[RMaskNRtn] {rMaskN ← FFF},	  c*, at[0C,10,RMaskNNNN];
	rMaskN ← u1FFF, RET[RMaskNRtn] {rMaskN ← 1FFF},		  c*, at[0D,10,RMaskNNNN];
	rMaskN ← u3FFF, RET[RMaskNRtn] {rMaskN ← 3FFF},		  c*, at[0E,10,RMaskNNNN];
	rMaskN ← RShift1 (~rMaskN xor rMaskN), RET[RMaskNRtn] {rMaskN ← 7FFF}, c*, at[0F,10,RMaskNNNN];
	rMaskN ← ~rMaskN xor rMaskN, RET[RMaskNRtn] {rMaskN ← FFFF}, c*, at[0,10,RMaskNNNN];

{LinkSet: landing spot for link-register setting, via a sequence such as the following:
	Xbus ← linkval, XDisp,					  c*;
	Xbus ← retnum, XDisp, pCalln, DISP4[LinkSet],		  c*;}
	RET[LinkSetRtn],					  c*, at[0,10,LinkSet];
	RET[LinkSetRtn],					  c*, at[1,10,LinkSet];
	RET[LinkSetRtn],					  c*, at[2,10,LinkSet];
	RET[LinkSetRtn],					  c*, at[3,10,LinkSet];
	RET[LinkSetRtn],					  c*, at[4,10,LinkSet];
	RET[LinkSetRtn],					  c*, at[5,10,LinkSet];
	RET[LinkSetRtn],					  c*, at[6,10,LinkSet];
	RET[LinkSetRtn],					  c*, at[7,10,LinkSet];
	RET[LinkSetRtn],					  c*, at[8,10,LinkSet];
	RET[LinkSetRtn],					  c*, at[9,10,LinkSet];
	RET[LinkSetRtn],					  c*, at[0A,10,LinkSet];
	RET[LinkSetRtn],					  c*, at[0B,10,LinkSet];
	RET[LinkSetRtn],					  c*, at[0C,10,LinkSet];
	RET[LinkSetRtn],					  c*, at[0D,10,LinkSet];
	RET[LinkSetRtn],					  c*, at[0E,10,LinkSet];
	RET[LinkSetRtn],					  c*, at[0F,10,LinkSet];