{File name:  GrayBltCtrl.mc
Description: Initialization and inter-item loops for GrayBlt opcodes.
Author: JPM
Created: July 9, 1986
Last Revised:
October 14, 1986 -- JPM -- add comments
September 5, 1986 -- JPM -- fix bugs in all opcodes at unusual boundary condition (src or dst item ends on page boundary & next page faults): must restore register 1
August 8, 1986 -- JPM -- fix bug in GRAYTHRSHLD introduced by last change (missed one constant!)
August 7, 1986 -- JPM -- change register & subroutine names, use symbolic constants
August 5, 1986 -- JPM -- handle case of height = 0 (all opcodes): note that "stackP←" moved to LoadGTable
July 24, 1986 -- JPM -- fix bug in GrBLTChgFlags (need to return to GrBLTLoadLinks)
July 23, 1986 -- JPM -- fix bugs in GRAYTHRSHLD (BumpBitVA parms not correct in one place, return bit offset not used in another place)
July 22, 1986 -- JPM -- add fault return from TRC mapping, fix bug in constants gr.L23.rev.* (didn't set reverse bit in L3)
July 18, 1986 -- JPM -- store start address of src and dest lines, adjust at entry
July 15, 1986 -- JPM -- fix bugs in GRAYSUM (return words reversed, page fault at end of item not handled correctly) and in GRAYTHRSHLD (no fault return points for initial src and dest mapping)
July 14, 1986 -- JPM -- fix bugs in all opcodes (table ptr high and low words reversed)
July 11, 1986 -- JPM -- make code live in bank 1
July 10, 1986 -- JPM -- invert rTemp at each return from Incr/DecrVA}

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

{initialization constants: see GrayBlt.dfn for referenced values}

Set[gr.L23.fwd.null,Or[Lshift[gr.fwd,4],gr.fwd,gr.null]],
Set[gr.L23.fwd.inv,Or[Lshift[gr.fwd,4],gr.fwd,gr.inv]],
Set[gr.L23.rev.null,Or[Lshift[gr.rev,4],gr.rev,gr.null]],
Set[gr.L23.rev.inv,Or[Lshift[gr.rev,4],gr.rev,gr.inv]];
Set[gr.L2.unaligned.fwd,Lshift[gr.unaligned.fwd,4]],
Set[gr.L2.trc.unaligned.fwd,Lshift[gr.trc.unaligned.fwd,4]],
Set[gr.L2.unaligned.rev,Lshift[gr.unaligned.rev,4]];
Set[gr.trcUnaligned.fwd,Or[gr.trc,gr.trc.unaligned.fwd]],
Set[gr.trcUnaligned.rev,Or[gr.trc,gr.trc.unaligned.rev]];
Set[gr.L4.trc,Lshift[gr.trc,4]],
Set[gr.L4.notTrc,Lshift[And[gr.writeDest.fwd,gr.readDest],4]];
Set[gr.L4.writeDest.fwd,Lshift[gr.writeDest.fwd,4]],
Set[gr.L4.writeDest.rev,Lshift[gr.writeDest.rev,4]],
Set[gr.L4.rotateSource.fwd,Lshift[gr.rotateSource.fwd,4]],
Set[gr.L4.rotateSource.rev,Lshift[gr.rotateSource.rev,4]],
Set[gr.L4.readDest,Lshift[gr.readDest,4]],
Set[gr.L4.trcUnaligned.fwd,Lshift[gr.trcUnaligned.fwd,4]],
Set[gr.L4.trcUnaligned.rev,Lshift[gr.trcUnaligned.rev,4]];

MacroDef[GrBLTEI,at[Or[#1,#2],10,GrBLTEIa]];

@GRAYBLT:
	rGrFF00 ← 0 - r0100, Xbus ← ErrnIBnStkp, XDisp, L0 ← L0.GrBLT,	c1, at[1,10,ESCAn];
	rTemp ← GBSizeLess1, push, BRANCH[GrBLTReentry,$,7],		c2;
	rhVirtualH ← STK, pop,						c3;

	Map ← rVirtualL ← [rhVirtualH, STK or rTemp], fXpop, fZpop, CALL[LoadTable], c1;
{LoadTable subroutine starts in c2, ends in c3}

	[] ← uGrHeight, ZeroBr,						c1, LoadTableRet[L0.GrBLT];
	rCount ← uGrWidth, BRANCH[$,GrBLTZeroHeight],			c2;
	rTemp ← uGrFlags, XHDisp,					c3;

{build images of link registers: L2 & L3 in rDstWord, L4 & L5 in rTemp}
	rTemp ← rTemp LRot8 {move dstFunc to low nibble}, DISP2[GrBLTL23], c1;
	rDstWord ← gr.L23.fwd.null, GOTO[GrBLTSetL4],			c2, at[0,4,GrBLTL23];
	rDstWord ← gr.L23.rev.null, GOTO[GrBLTSetL4],			c2, at[1,4,GrBLTL23];
	rDstWord ← gr.L23.fwd.inv, GOTO[GrBLTSetL4],			c2, at[2,4,GrBLTL23];
	rDstWord ← gr.L23.rev.inv, GOTO[GrBLTSetL4],			c2, at[3,4,GrBLTL23];
GrBLTSetL4:
	rGr00FF ← r0100 - 1, Xbus ← rTemp LRot12, XDisp,		c3;

	rTemp ← rTemp and 6 {isolate dstFunc}, ZeroBr, DISP4[GrBLTL4,6], c1;
	BRANCH[GrBLTL4OK,GrBLTL4NoRead],				c2, at[6,10,GrBLTL4] {fwd, ~trc};
	rTemp ← rTemp or gr.L4.trc, BRANCH[GrBLTL4TRCOK,GrBLTL4TRCNoRead], c2, at[7,10,GrBLTL4] {fwd, trc};
	rTemp ← rTemp or gr.L4.readDest, BRANCH[GrBLTL4OK,GrBLTL4NoRead], c2, at[0E,10,GrBLTL4] {rev, ~trc};
	rTemp ← rTemp or gr.L4.trc, BRANCH[GrBLTL4TRCOK,GrBLTL4TRCNoRead], c2, at[0F,10,GrBLTL4] {rev, trc};
GrBLTL4OK:
	rTemp ← rTemp or gr.L4.readDest, GOTO[GrBLTCheckAlignment],	c3;
GrBLTL4NoRead:
	rTemp ← rTemp or gr.L4.writeDest.fwd, GOTO[GrBLTCheckAlignment], c3;
{NOTE: gr.L4.readDest or gr.L4.writeDest.fwd = gr.L4.writeDest.rev, if from rev, ~trc above}
GrBLTL4TRCOK:
	GOTO[GrBLTCheckAlignment],					c3;
GrBLTL4TRCNoRead:
	rDstWord ← rDstWord or gr.trc.set,				c3;

GrBLTCheckAlignment: {source and destination byte alignment}
	Q ← uGrSrcByte,							c1;
	[] ← Q xor uGrDstByte, NZeroBr,					c2;
	[] ← rDstWord and gr.rev, NZeroBr, BRANCH[GrBLTLinksOK,$],	c3;

	Xbus ← rTemp LRot12, XDisp, BRANCH[$,GrBLTURev],		c1;
GrBLTUFwd:
	rDstWord ← rDstWord or gr.L2.unaligned.fwd, DISP4[GrBLTL4U,0A], c2;
GrBLTURev:
	rDstWord ← rDstWord or gr.L2.unaligned.rev, DISP4[GrBLTL4U,0A], c2;
	[] ← rDstWord and gr.rev, NZeroBr, GOTO[GrBLTUTRC],		c3, at[0A,10,GrBLTL4U] {trc};
	GOTO[GrBLTLinksOK],						c3, at[0E,10,GrBLTL4U] {~trc, ~set};
	rTemp ← rTemp xor 20, GOTO[GrBLTLinksOK],			c3, at[0F,10,GrBLTL4U] {~trc, set};
{NOTE: gr.L4.writeDest.* xor 20 = gr.L4.rotateSource.*}

GrBLTUTRC:
	rDstWord ← rDstWord and ~60, BRANCH[GrBLTUFTRC,GrBLTURTRC],	c1;
GrBLTUFTRC:
	rDstWord ← rDstWord or gr.L2.trc.unaligned.fwd,			c2;
	rTemp ← rTemp or gr.L4.trcUnaligned.fwd, GOTO[GrBLTLinksOK],	c3;
GrBLTURTRC:
	rDstWord ← rDstWord or gr.L2.unaligned.rev,			c2;
	rTemp ← rTemp or gr.L4.trcUnaligned.rev,			c3;

GrBLTLinksOK:
	rDstWord ← rDstWord LRot8, CANCELBR[$,0F],			c1;
	rTemp ← rTemp or rDstWord, NegBr,				c2;
	uGrFlags ← rTemp, BRANCH[GrBLTLoadLinks,$],			c3;

{adjust src and dest addrs to point to the last pixel of the item}
	rVirtualL ← uGrDstLow, L1 ← L1.GrBLTDstEOL,			c1;
	rhVirtualH ← uGrDstHigh,					c2;
	rTemp ← uGrDstByte,						c3;

	rTemp ← rTemp + rCount,						c1;
	rTemp ← rTemp - 1, CALL[BumpByteVA],				c2;
{BumpByteVA subroutine starts in c3, ends in c1}
	uGrDstLow ← rVirtualL,						c2, BumpByteVARet[L1.GrBLTDstEOL];
	uGrDstHigh ← Q,							c3;

	uGrDstByte ← ~rTemp,						c1;
	rVirtualL ← uGrSrcLow, L1 ← L1.GrBLTSrcEOL,			c2;
	rhVirtualH ← uGrSrcHigh,					c3;

	rTemp ← uGrSrcByte,						c1;
	rTemp ← rTemp + rCount,						c2;
	rTemp ← rTemp - 1, CALL[BumpByteVA],				c3;

{BumpByteVA subroutine starts in c1, ends in c2}
	uGrSrcLow ← rVirtualL,						c3, BumpByteVARet[L1.GrBLTSrcEOL];

	uGrSrcHigh ← Q,							c1;
	uGrSrcByte ← ~rTemp,						c2;
GrBLTGoLoadLinks:
	GOTO[GrBLTLoadLinks],						c3;

GrBLTReentry:
	rGr00FF ← r0100 - 1, pop,					c3;

GrBLTLoadLinks:
	rTemp ← uGrFlags, XDisp,					c1;
	L5 ← 0, Xbus ← L1.GrBLTSetL5, XDisp, DISP4[LinkSet],		c2;
{LinkSet used to set register; starts and ends in c3}

	Xbus ← rTemp LRot12, XDisp,					c1, LinkSetRet[L1.GrBLTSetL5];
	L4 ← 0, Xbus ← L1.GrBLTSetL4, XDisp, DISP4[LinkSet],		c2;
{LinkSet used to set register; starts and ends in c3}

	Xbus ← rTemp LRot8, XDisp,					c1, LinkSetRet[L1.GrBLTSetL4];
	L3 ← 0, Xbus ← L1.GrBLTSetL3, XDisp, DISP4[LinkSet],		c2;
{LinkSet used to set register; starts and ends in c3}

	Xbus ← rTemp LRot4, XDisp,					c1, LinkSetRet[L1.GrBLTSetL3];
	L2 ← 0, Xbus ← L1.GrBLTSetL2, XDisp, DISP4[LinkSet],		c2;
{LinkSet used to set register; starts and ends in c3}

GrBLTMapVirtual:
	rTemp ← uGrFlags, XwdDisp, L0 ← L0.GrBLTTRC,			c1, LinkSetRet[L1.GrBLTSetL2];
	rVirtualL ← uGrTRCLow, BRANCH[GrBLTMapTRC,$,1],			c2;
	rhGrDispCond ← rTemp LRot12, GOTO[GrBLTMapSrcAndDst],		c3;
GrBLTMapTRC:
	rhVirtualH ← uGrTRCHigh, CALL[MapSrc],				c3;

{MapSrc subroutine starts in c1, ends in c2}
	rhGrDispCond ← rTemp LRot8,					c3, MapSrcRet[L0.GrBLTTRC];

	rGrTRC ← rSrcReal,						c1;
	rSrcReal ← rhSrcReal,						c2;
	rhGrTRC ← rSrcReal LRot0,					c3;

GrBLTMapSrcAndDst:
	rVirtualL ← uGrDstLow, L1 ← L1.GrBLTAdjDst,			c1;
	rTemp ← uGrDstByte, L2Disp,					c2;
	Q ← uGrWidth, BRANCH[$,GrAdjDstNeg,7],				c3;

{if returning from interrupt or page fault, may need to adjust virtual addrs}
	Q ← Q - rCount, ZeroBr, GOTO[GrAdjDstCont],			c1;
GrAdjDstNeg:
	Q ← rCount - Q, ZeroBr,						c1;
GrAdjDstCont:
	rTemp ← rTemp + Q, NegBr, BRANCH[$,GrBLTAdjDstOK],		c2;
	rhVirtualH ← uGrDstHigh, BRANCH[BumpByteVA,BumpByteVANeg],	c3;

{BumpByteVA subroutine starts in c1, ends in c2}
	rTemp ← ~rTemp, GOTO[GrBLTAdjDstStore],				c3, BumpByteVARet[L1.GrBLTAdjDst];
GrBLTAdjDstOK:
	rhVirtualH ← Q ← uGrDstHigh, CANCELBR[$],			c3;

GrBLTAdjDstStore:
	uGrCurrDstLow ← rVirtualL, L0 ← L0.GrBLT,			c1;
	uGrCurrDstHigh ← Q,						c2;
	CALL[MapDst],							c3;

{MapDst subroutine starts in c1, ends in c2}
GrBLTMapDstRet:
	Noop,								c3, MapDstRet[L0.GrBLT];

	CALL[GrAdjustSrc],						c1;
{GrAdjustSrc subroutine starts in c2, calls MapSrc which ends in c2}
GrBLTMapSrcRet:
	[] ← rTemp, NZeroBr, L2Disp, GOTO[GrayBltStart],		c3, MapSrcRet[L0.GrBLT];

{abnormal return points}
	rCount ← rCount + 2,						c3, MapGrSrcI[L0.GrBLTLoop];

	Noop,								c1;
	Noop,								c2;
GrBLTInt:
	r0100 ← 0FF + 1, GOTO[Bank1Interrupt],				c3;

	rCount ← rCount - 1, NegBr, GOTO[GrBLTPageFault],		c3, MapSrcF[L0.GrBLT];
	rCount ← rCount - 1, GOTO[GrBLTPageFault],			c3, MapSrcF[L0.GrBLTTRC];
	rCount ← rCount + 1, NegBr, GOTO[GrBLTPageFault],		c3, MapSrcF[L0.GrBLTLoop];

	rCount ← rCount - 1, NegBr, GOTO[GrBLTPageFault],		c3, MapDstF[L0.GrBLT];
	rCount ← rCount - 1, NegBr,					c3, MapDstF[L0.GrBLTLoop];

GrBLTPageFault:
	rCount ← rCount + 1, BRANCH[$,GrBLTEIa],			c1;
	r0100 ← 0FF + 1, GOTO[Bank1Fault],				c2;

{normal return points}
GrayBltEndItem:
	CANCELBR[GrBLTEIa,0F],						c1;
GrayBltEndItemSrcPageCross:
	CANCELBR[$,0F],							c1;
GrBLTEIa:
	Q ← uGrHeight,							c2;
	Q ← Q - 1, ZeroBr,						c3;

	uGrHeight ← Q, BRANCH[$,GrBLTDone],				c1;
	rVirtualL ← uGrDstLow, L1 ← L1.GrBLTDstNextItem,		c2;
	rTemp ← uGrDstByte,						c3;

	Q ← uGrDstBPL,							c1;
	rTemp ← Q + rTemp, NegBr,					c2;
	rhVirtualH ← uGrDstHigh, BRANCH[BumpByteVA,BumpByteVANeg],	c3;

{BumpByteVA subroutine starts in c1, ends in c2}
	uGrDstLow ← rVirtualL, L0 ← L0.GrBLTInt,			c3, BumpByteVARet[L1.GrBLTDstNextItem];

	uGrDstHigh ← Q,							c1;
	uGrDstByte ← ~rTemp, CALL[GrSrcNextItem],			c2;
{GrSrcNextItem subroutine starts in c3, returns here (effect of interrupt deferred)}

{compare BPL values: if same value (modulo 2), link registers are OK}
	Q ← uGrSrcBPL,							c1, at[L0.GrBLTInt,10,GrSrcNextItemRtn];
	Q ← Q xor uGrDstBPL,						c2;
	[] ← Q and 1, NZeroBr,						c3;

	rTemp ← uGrFlags, MesaIntBr, BRANCH[$,GrBLTChgFlags],		c1;
GrBLTCheckInt:
	rCount ← uGrWidth, BRANCH[$,GrBLTInt],				c2;
	GOTO[GrBLTMapVirtual],						c3;

GrBLTChgFlags: {source/destination alignment has changed, affecting link regs L2 and L4}
	rTemp ← rTemp LRot8, L4Disp, CANCELBR[$],			c2;
	Q ← 20, L2Disp, DISP4[GrBLTChgF],				c3;
{rTemp now contains L2 image in bits 8-11; Q will contain L4 changes}

	Q ← 0, BRANCH[GrBLTChgFa,GrBLTChgFb,7],				c1, at[gr.readDest,10,GrBLTChgF];
	rTemp ← rTemp xor 40, CANCELBR[GrBLTChgFe,0F],			c1, at[gr.writeDest.fwd,10,GrBLTChgF];
	rTemp ← rTemp xor 60, CANCELBR[GrBLTChgFe,0F],			c1, at[gr.writeDest.rev,10,GrBLTChgF];
	rTemp ← rTemp xor 40, CANCELBR[GrBLTChgFe,0F],			c1, at[gr.rotateSource.fwd,10,GrBLTChgF];
	rTemp ← rTemp xor 60, CANCELBR[GrBLTChgFe,0F],			c1, at[gr.rotateSource.rev,10,GrBLTChgF];
	rTemp ← rTemp xor 60, BRANCH[GrBLTChgFc,GrBLTChgFd,7],		c1, at[gr.trc,10,GrBLTChgF];
	rTemp ← rTemp xor 20, CANCELBR[GrBLTChgFe,0F],			c1, at[gr.trcUnaligned.fwd,10,GrBLTChgF];
	rTemp ← rTemp xor 60, CANCELBR[GrBLTChgFd,0F],			c1, at[gr.trcUnaligned.rev,10,GrBLTChgF];
GrBLTChgFa:
	rTemp ← rTemp xor 40, GOTO[GrBLTChgFz],				c2;
GrBLTChgFb:
	rTemp ← rTemp xor 60, GOTO[GrBLTChgFz],				c2;
GrBLTChgFc:
	rTemp ← rTemp xor 40, GOTO[GrBLTChgFz],				c2;
GrBLTChgFd:
	Q ← 30, GOTO[GrBLTChgFz],					c2;
GrBLTChgFe:
	Noop,								c2;
GrBLTChgFz:
	rTemp ← rTemp LRot8 xor Q, MesaIntBr,				c3;

	uGrFlags ← rTemp, BRANCH[$,GrBLTChgFInt],			c1;
	rCount ← uGrWidth, GOTO[GrBLTGoLoadLinks],			c2;
GrBLTChgFInt:
	rCount ← uGrWidth, GOTO[GrBLTInt],				c2;

GrBLTDone:
	r0100 ← rGr00FF + 1,						c2;
GrBLTZeroHeight:
	stackP ← 0, GOTO[Bank1NxtInstc1],				c3;

@GRAYSUM:
	rGrFF00 ← 0 - r0100, Xbus ← ErrnIBnStkp, XDisp, L0 ← L0.GrSum,	c1, at[2,10,ESCAn];
	rTemp ← SumSizeLess1, push, BRANCH[GrSumReentry,$,7],		c2;
	rhVirtualH ← STK, pop,						c3;

	Map ← rVirtualL ← [rhVirtualH, STK or rTemp], fXpop, fZpop,	c1;
	rTemp ← SumLastIndex, L1 ← 0, push, CALL[LoadTableSideDoor],	c2;
{LoadTableSideDoor subroutine starts in c3, ends in c3}

	[] ← uGrHeight, ZeroBr,						c1, LoadTableRet[L0.GrSum];
	uGrSumLow ← rSumLow ← 0, BRANCH[$,GrSumZeroHeight],		c2;
	uGrSumHigh ← rSumHigh ← 0,					c3;

GrSumStartItem:
	rCount ← uGrWidth, L2 ← 0, CALL[GrAdjustSrc],			c1, at[L0.GrSum,10,GrSrcNextItemRtn];

GrSumReentry:
	rSumLow ← uGrSumLow, pop,					c3;

	rSumHigh ← uGrSumHigh, L2 ← 0, CALL[GrAdjustSrc],		c1;
{GrAdjustSrc subroutine starts in c2, calls MapSrc which ends in c2}
GrSumMapRet:
	[] ← rTemp, NZeroBr, GOTO[SumItemStart],			c3, MapSrcRet[L0.GrSum];

{abnormal return points}
	uGrSumHigh ← rSumHigh, GOTO[Bank1Interrupt],			c3, MapGrSrcI[L0.GrSumLoop];

	[] ← rCount, ZeroBr, GOTO[GrSumSrcPageFault],			c3, MapSrcF[L0.GrSum];
	[] ← rCount, ZeroBr,						c3, MapSrcF[L0.GrSumLoop];

GrSumSrcPageFault:
	rTemp ← uGrHeight, BRANCH[GrSumPageFault,$],			c1;
	rSumLow ← uGrSumLow, L0 ← L0.GrSum, GOTO[GrSumEIb],		c2;
GrSumPageFault:
	uGrSumHigh ← rSumHigh, GOTO[Bank1Fault],			c2;

{normal return point}
SumEndItem:
	rTemp ← uGrHeight, BRANCH[$,GrSumEIa],				c1;
	L0 ← L0.GrSum, GOTO[GrSumEIb],					c2;
GrSumEIa:
	rSumHigh ← rSumHigh + 1, L0 ← L0.GrSum,				c2;
GrSumEIb:
	rTemp ← rTemp - 1, ZeroBr,					c3;

	uGrHeight ← rTemp, BRANCH[$,GrSumDone],				c1;
	CALL[GrSrcNextItem],						c2;
{GrSrcNextItem subroutine starts in c3, returns to GrSumStartItem above or GrSumInt below}

GrSumInt:
	rCount ← uGrWidth,						c1, at[L0.GrSumInt,10,GrSrcNextItemRtn];
	uGrSumLow ← rSumLow,						c2;
	uGrSumHigh ← rSumHigh, GOTO[Bank1Interrupt],			c3;

GrSumZeroHeight:
	uGrSumHigh ← rSumHigh ← 0, GOTO[GrSumExit],			c3;

GrSumDone:
	uGrSumLow ← rSumLow,						c2;
	uGrSumHigh ← rSumHigh,						c3;

GrSumExit:
	Noop,								c1;
	TOS ← uGrSumHigh,						c2;
	stackP ← 2, GOTO[Bank1NxtInstc1],				c3;

@GRAYTHRSHLD:
	rGrFF00 ← 0 - r0100, Xbus ← ErrnIBnStkp, XDisp, L0 ← L0.GrThreshold, c1, at[3,10,ESCAn];
	rTemp ← ThresholdSizeLess1, push, BRANCH[GrThreshReentry,$,7],	c2;
	rhVirtualH ← STK, pop,						c3;

	Map ← rVirtualL ← [rhVirtualH, STK or rTemp], fXpop, fZpop, CALL[LoadTable], c1;
{LoadTable subroutine starts in c2, ends in c3}

	[] ← uGrHeight, ZeroBr, push,					c1, LoadTableRet[L0.GrThreshold];
	uGrDstWord ← rDstWord ← 0, BRANCH[$,GrThreshZeroHeight],	c2;
	rCount ← uGrWidth, GOTO[GrThreshMapDst],			c3;

GrThreshReentry:
	rDstWord ← uGrDstWord, pop,					c3;

GrThreshMapDst:
	Noop,								c1;
GrThreshMapDstCont:
	rVirtualL ← uGrDstLow, L1 ← L1.GrThresholdAdjDst,		c2;
	rTemp ← uGrDstBit,						c3;

	Q ← uGrWidth,							c1;
	Q ← Q - rCount, ZeroBr,						c2;
	Q ← rTemp + Q, BRANCH[$,GrThreshAdjDstOK],			c3;

	rhVirtualH ← uGrDstHigh, CALL[BumpBitVA],			c1;
{BumpBitVA subroutine starts in c2, returns at GrThreshAdjDstStore}

GrThreshAdjDstOK:
	rhVirtualH ← Q ← uGrDstHigh,					c1;
GrThreshAdjDstStore:
	uGrCurrDstLow ← rVirtualL,					c2, at[L1.GrThresholdAdjDst,10,BumpByteVARtn];
	uGrCurrDstHigh ← Q, CALL[MapDst],				c3;

{MapDst subroutine starts in c1, ends in c2}
GrThreshMapDstRet:
	Q ← MD,								c3, MapDstRet[L0.GrThreshold];

	[] ← rDstWord, NZeroBr,						c1;
	rhTemp ← rTemp LRot0, ZeroBr, BRANCH[$,GrThreshDWOK],		c2;
	Q ← Q or 1, BRANCH[$,GrThreshDstWord1],				c3;

	CALL[LRotateN],							c1;
{LRotateN subroutine takes 5 cycles: starts in c2, ends in c3}

	rMaskN ← LShift1 rMaskN, SE ← 1,				c1, LRotateNRet[L0.GrThreshold];
	rDstWord ← rTemp and rMaskN, GOTO[GrThreshDWOK],		c2;

GrThreshDstWord1:
	rDstWord ← 1,							c1;
	Noop,								c2;
GrThreshDWOK:
	uGrDstWord ← rDstWord, CANCELBR[$,1],				c3;

	rThreshold ← uGrThreshold, L2 ← 0, CALL[GrAdjustSrc],		c1;
{GrAdjustSrc subroutine starts in c2, calls MapSrc which ends in c2}
GrThreshMapSrcRet:
	[] ← rTemp, NZeroBr, GOTO[ThreshItemStart],			c3, MapSrcRet[L0.GrThreshold];

{abnormal return points}
	GOTO[Bank1Interrupt],						c3, MapGrSrcI[L0.GrThresholdLoop];
	GOTO[Bank1Interrupt],						c3, MapGrSrcI[L0.GrThresholdExtra];

	[] ← rCount, ZeroBr, GOTO[GrThreshSrcPageFault],		c3, MapSrcF[L0.GrThreshold];
	[] ← rCount, ZeroBr, GOTO[GrThreshSrcPageFault],		c3, MapSrcF[L0.GrThresholdLoop];
	[] ← rCount, ZeroBr,						c3, MapSrcF[L0.GrThresholdExtra];

GrThreshSrcPageFault:
	MAR ← [rhDstReal, rDstReal + 0], BRANCH[GrThreshSPFa,$],	c1;
	Q ← 0, GOTO[GrThreshLWa],					c2;
GrThreshSPFa:
	GOTO[Bank1Fault],						c2;

	[] ← rCount, ZeroBr, GOTO[GrThreshDstPageFault],		c3, MapDstF[L0.GrThreshold];
	[] ← rCount, ZeroBr, GOTO[GrThreshDstPageFault],		c3, MapDstF[L0.GrThresholdLoop];
	rCount ← rCount - 1, ZeroBr,					c3, MapDstF[L0.GrThresholdExtra];

GrThreshDstPageFault:
	BRANCH[GrThreshDPFa,$],						c1;
	GOTO[GrThreshLWd],						c2;
GrThreshDPFa:
	GOTO[Bank1Fault],						c2;

{normal return point}
ThreshEndItem:
	MAR ← [rhDstReal, rDstReal + 0], BRANCH[GrThreshLastWord,$],	c1;
	MDR ← rDstWord, GOTO[GrThreshLWd],				c2;
GrThreshLastWord:
	Q ← 0,								c2;
GrThreshLWa:
	rTemp ← MD,							c3;

GrThreshLWb:
	rDstWord ← DLShift1 rDstWord, SE ← 0, NegBr,			c1;
	BRANCH[$,GrThreshLWc],						c2;
	GOTO[GrThreshLWb],						c3;

GrThreshLWc:
	Q ← rTemp and Q,						c3;

	MAR ← [rhDstReal, rDstReal + 0],				c1;
	MDR ← rDstWord or Q,						c2;
GrThreshLWd:
	rTemp ← uGrHeight, L0 ← L0.GrThreshold,				c3;

	rTemp ← rTemp - 1, ZeroBr,					c1;
	uGrHeight ← rTemp, BRANCH[$,GrThreshDone],			c2;
	rVirtualL ← uGrDstLow, L1 ← L1.GrThresholdDstNextItem,		c3;

	rTemp ← uGrDstBit,						c1;
	Q ← uGrDstBPL,							c2;
	Q ← Q + rTemp,							c3;

	rhVirtualH ← uGrDstHigh, CALL[BumpBitVA],			c1;
{BumpBitVA subroutine starts in c2, ends in c1}

	uGrDstLow ← rVirtualL,						c2, at[L1.GrThresholdDstNextItem,10,BumpByteVARtn];
	uGrDstHigh ← Q,							c3;

	uGrDstBit ← rTemp,						c1;
	rCount ← uGrWidth, CALL[GrSrcNextItem],				c2;
{GrSrcNextItem subroutine starts in c3, returns here or to GrThreshInt below}

	uGrDstWord ← rDstWord ← 0, GOTO[GrThreshMapDstCont],		c1, at[L0.GrThreshold,10,GrSrcNextItemRtn];

GrThreshInt:
	uGrDstWord ← 0, Bank ← bank0, GOTO[Bank1Intc2],			c1, at[L0.GrThresholdInt,10,GrSrcNextItemRtn];

GrThreshDone:
	stackP ← 0, GOTO[Bank1NxtInstc1],				c3;

GrThreshZeroHeight:
	stackP ← 0, GOTO[Bank1NxtInstc1],				c3;

{common routine for adjusting source address upon reentry}

GrAdjustSrc:
	rVirtualL ← uGrSrcLow, L1 ← L1.GrAdjSrc,			c2;
	rTemp ← uGrSrcByte, L2Disp,					c3;

	Q ← uGrWidth, BRANCH[$,GrAdjSrcNeg,7],				c1;
	Q ← Q - rCount, ZeroBr, GOTO[GrAdjSrcCont],			c2;
GrAdjSrcNeg:
	Q ← rCount - Q, ZeroBr,						c2;
GrAdjSrcCont:
	rTemp ← rTemp + Q, NegBr, BRANCH[$,GrAdjSrcOK],			c3;

	rhVirtualH ← uGrSrcHigh, BRANCH[BumpByteVA,BumpByteVANeg],	c1;
{BumpByteVA subroutine starts in c2, ends in c3}

	rTemp ← ~rTemp, GOTO[GrAdjSrcStore],				c1, BumpByteVARet[L1.GrAdjSrc];
GrAdjSrcOK:
	rhVirtualH ← Q ← uGrSrcHigh, CANCELBR[$],			c1;
GrAdjSrcStore:
	uGrCurrSrcLow ← rVirtualL,					c2;
	uGrCurrSrcHigh ← Q, CALL[MapSrc],				c3;

{MapSrc subroutine starts in c1, returns to caller}

{common routine for adjusting source address to next item}

GrSrcNextItem:
	rVirtualL ← uGrSrcLow, L1 ← L1.GrSrcNextItem,			c3;

	rTemp ← uGrSrcByte,						c1;
	Q ← uGrSrcBPL,							c2;
	rTemp ← Q + rTemp, NegBr,					c3;

	rhVirtualH ← uGrSrcHigh, BRANCH[BumpByteVA,BumpByteVANeg],	c1;
{BumpByteVA subroutine starts in c2, ends in c3}

	uGrSrcLow ← rVirtualL,						c1, BumpByteVARet[L1.GrSrcNextItem];
	uGrSrcHigh ← Q, MesaIntBr, L0Disp,				c2;
	uGrSrcByte ← rTemp ← ~rTemp, DISP4[GrSrcNextItemRtn],		c3;

{temporary BumpBitVA routine, until BumpBitAddress is incorporated}

BumpBitVA:
	rTemp ← Q and ~0F,						c*;
IncrDecrBitVA:
	rTemp ← rTemp LRot12,						c*;
	rVirtualL ← rVirtualL + rTemp, CarryBr,				c*;

	rTemp ← Q and 0F, BRANCH[IncrVANoCarry,IncrVACarry],		c*;

{returns through BumpByteVARet}