{
	File name: BandBLTSubs.mc
	Description: Subroutines to support BandBLT byte-code
	Author: Patrick PXO     
	Created: June 10, 1980  2:40 PM
	Last edit by CRF,       26-Oct-86 12:17:18	Replaced uRect* by uLO*; changed the TrapezoidLOLoop exit test to subtraction from xor for readability.
	Last edit by CRF,       22-Jul-86 16:32:24	Add code to writeLO to
	  handle trapezoid leftovers.
	Last edit by RDH     ,  30-Oct-85 13:46:36	Change to work with workstation byte codes on Daybreak(textblt)
	Last edit by Jim JXF     ,  January 23, 1981  10:54 AM

	Last edit by PXO     ,  April 21, 1981  4:37 PM:  Changed a  "BRANCH[$, justEob, 1]" to "BRANCH[$, justEob, 0D]."
	Last edit by PXO     ,  March 23, 1981  4:10 PM:  Changed spellings of all occurrences of "uregMumble" to "uMumble."
	Last edit by PXO     ,  March 20, 1981  7:57 PM:  Changed writeLO to write SetLevel and SetInk commands if needed before
	  writing leftovers.
	Last edit by Dennis DEG     ,  1-Sep-84 19:17:19:  Add copyright notice.
	  
}

{ 	Copyright (C) 1980, 1981 by Xerox Corporation.  All rights reserved.}



{
	Subroutine writeLO is called to write an entry in the output leftover
	list.  The number of words to be written is encoded in rJunk.  If rJunk
	contains 0C, only uLO2 (i.e., an end-of-band command) will be stored
	in memory; if it contains 0, the words written are uLO0, uLO1, and
	uLO2.  If the microcode was assembled for two banks of control store,
	trapezoids are enabled.  In this case, if rJunk contains 0 AND link
	register 1 bit 1 is set (x1xx), the words written are uLO0, uLO1,
	uLO2, and the last seven words of the trapezoid interpolators.  The
	pointer to the leftover list is in uSaveLOwritePHigh,,uSaveLOwritePLow;
	it is updated and saved before the subroutine returns.  Before writing
	the leftover, uCurrentLevelCmd is compared to uLastLevelLOwritten; if
	they differ,uCurrentLevelCmd is written to the output leftover list and
	uLastLevelLOwritten is set to uCurrentLevelCmd.  Similarly,
	uCurrentInkCmd is compared to uLastInkLOwritten; if they differ,
	uCurrentInkCmd is written to the output leftover list and
	uLastInkLOwritten is set to uCurrentInkCmd.  Note that these tests are
	skipped if Link register 1 has bit 2 set (xx1x); this is to
	avoid writing SetInk and SetLevel leftover list entries when writing
	end-of-band commands to the output leftover list.  This puts the
	obvious constraints on the values that can be used for subroutine
	linkage.  writeLO modifies link register L2, and returns through label
	writeLORets via link register L1.
}

writeLO:
	rLOwriteP ← uSaveLOwritePLow, L1Disp,				c1, at[writeLO.0, 10, writeLORets];
	rhLOwriteP ← uSaveLOwritePHigh, BRANCH[$, justEob, 0D],		c2;
	rTemp ← uCurrentLevelCmd, pCall2,				c3;

	[] ← rTemp xor uLastLevelLOwritten, ZeroBr,			c1, at[5, 10];
	rScratch ← xMaxdValIntPlus1 {for TrapezoidLOLoop}, BRANCH[$, TestInk], c2;
	uLastLevelLOwritten ← rTemp,					c3, at[4, 10, NoCross];

	rLOwriteP ← MAR ← [rhLOwriteP, rLOwriteP + 1],			c1;
	MDR ← rTemp, PgCrBRANCH[LevNoCross, $],				c2;
	rScratch ← uLOwriteV, CALL[updatePgNum],			c3, at[7, 10, NoCross];
LevNoCross:
TestInk:
	rLoop ← uCurrentInkCmd, pCall2	,c3, at[5, 10, NoCross];

	Ybus ← rLoop xor uLastInkLOwritten, ZeroBr	,c1, at[9, 10];
	uLastInkLOwritten ← rLoop, BRANCH[$, InkNoCross]	,c2;
	Noop	,c3, at[8, 10, NoCross];

	rLOwriteP ← MAR ← [rLOwriteP, rLOwriteP + 1]	,c1;
	MDR ← rLoop, rTemp ← rLoop, PgCrBRANCH[InkNoCross, $]	,c2;
	rScratch ← uLOwriteV, CALL[updatePgNum]	,c3, at[0B, 10, NoCross];
InkNoCross:
	Ybus ← rJunk, YDisp, GOTO[LOwriteLoop]	,c3, at[9, 10, NoCross];
justEob:
	Ybus ← rJunk, YDisp, GOTO[LOwriteLoop]	,c3;

LOwriteLoop:
	rLOwriteP ← MAR ← [rhLOwriteP, rLOwriteP + 1], pCall2, DISP4[writec2]	,c1;
writec2:
	MDR ← uLO0, rTemp ← uLO0, DISP4{PgCrBRANCH}[NoCross{, reWrite}]	,c2, at[0, 10];
	MDR ← uLO1, rTemp ← uLO1, DISP4{PgCrBRANCH}[NoCross{, reWrite}]	,c2, at[6, 10, writec2];
	MDR ← uLO2, rTemp ← uLO2, DISP4{PgCrBRANCH}[LOwriteDone{, LastCross}, 0C]	,c2, at[0C, 10, writec2];
NoCross:
	rJunk ← rJunk + 6, YDisp, GOTO[LOwriteLoop]	,c3, at[0, 10];
AnotherNoCross:
	rJunk ← rJunk + 6, YDisp, GOTO[LOwriteLoop]	,c3, at[6, 10, NoCross];


LastCross:
	rScratch ← uLOwriteV, CALL[updatePgNum]	,c3, at[0E, 10, NoCross];

reWrite:
	rScratch ← uLOwriteV, CALL[updatePgNum]	,c3, at[2, 10, NoCross];

updatePgNum:
	rhLOwriteV ← rLOwriteV ← rScratch LRot8	,c1;
	rScratch ← rScratch + 1	,c2;
	uLOwriteV ← rScratch	,c3;

	Map ← [rhLOwriteV, rLOwriteV]	,c1;
	rScratch ← xMaxdValIntPlus1	,c2; {for TrapezoidLOLoop}
	rhLOwriteP ← rLOwriteP ← MD	,c3;

	rLOwriteP ← MAR ← [rhLOwriteP, 0 + 0], pRet2	,c1;
	MDR ← rTemp, RET[NoCross]	,c2;

IfEqual[thereAreTwoBanks,1,SkipTo[TwoBankCase],];

{OneBankCase (no trapezoids)}

LOwriteDone:
	Noop	,c3, at[0C, 10, NoCross];

	uSaveLOwritePLow ← rLOwriteP	,c1;
	rLOwriteP ← rhLOwriteP, pRet1	,c2;
	uSaveLOwritePHigh ← rLOwriteP, RET[writeLORets]	,c3;

{OneBankCaseEnd}
SkipTo[TwoBankCaseEnd];

TwoBankCase! {(trapezoids)}

LOwriteDone:
	L1Disp, rJunk ← xMinValInt			,c3, at[0C, 10, NoCross];

LOExit:
	uSaveLOwritePLow ← rLOwriteP, BRANCH[$, TrapezoidLOLoop, 0B] ,c1;
	rLOwriteP ← rhLOwriteP, pRet1			,c2;
	uSaveLOwritePHigh ← rLOwriteP, RET[writeLORets]	,c3;

{The loop below writes out the last seven words of a trapezoid leftover.}
TrapezoidLOLoop:
	Ybus ← rJunk, rScratch ← rScratch - rJunk, AltUaddr, ZeroBr	,c2;
	{rScratch is written above only to meet microcode encoding constraints}
	rTemp ← uyBlk0, BRANCH[$, LOExit]		,c3;
	{Note no branch condition in above instruction; this effectively turns
	the following BRANCH at LOExit into a GOTO[$]}

	rLOwriteP ← MAR ← [rhLOwriteP, rLOwriteP + 1], pCall2	,c1;
	MDR ← rTemp, PgCrBRANCH[$, RewriteTrapezoid]	,c2, at[0D, 10];
	rJunk ← rJunk + 1				,c3, at[0D, 10, NoCross];

	rScratch ← xMaxdValIntPlus1, GOTO[TrapezoidLOLoop]	,c1;
	{rScratch has to be reset above every time through the loop even though
        its value doesn't change, because microcode encoding constraints require
	it to be written (and smashed) on the loop exit test above}


RewriteTrapezoid:
	rScratch ← uLOwriteV, CALL[updatePgNum]		,c3, at[0F, 10, NoCross];

TwoBankCaseEnd!

{
	Subroutine Read is called to read the memory word addressed by the virtual pointer in [rhReadV,,rReadV].  It loads
	[rhReadP,,rReadP] with the physical pointer to this word, and loads uVirtPage and rJunk with the next virtual page number.  The
	Map is neither checked nor maintained.  The memory word is returned in rTemp.  Read returns through label ReadRets.
}
Read:
	rTemp ← rReadV	,c1;
	rReadV ← rReadV and ~00FF	,c2;
	rReadV ← rReadV or rhReadV	,c3;

	rReadV ← rReadV LRot8 {virtual page number}	,c1;
	rReadP ← rReadV + 1 {next virtual page}	,c2;
	rReadV ← rTemp	,c3;

ReadMap:
	Map ← [rhReadV, rReadV]	,c1;
	uVirtPage ← rReadP	,c2;
	rhReadP ← rReadP ← MD	,c3;

	rReadP ← MAR ← [rhReadP, rReadV + 0]	,c1;
	rJunk ← uVirtPage, pRet2	,c2;
	rTemp ← MD, RET[ReadRets]	,c3;



{
	Subroutine reRead is called when the physical pointer in [rhReadP,,rReadP] crosses a page.  It requires rTemp to contain
	the virtual page number of the page to be read, and returns in rTemp the first word of this page.  It leaves [rhReadP,,rReadP]
	pointing to this word, and loads uVirtPage and rJunk with the next virtual page number.  The Map is neither checked nor maintained.
	reRead uses subroutine Read and returns through label ReadRets.
}
reRead:
	rhReadV ← rReadV ← rTemp LRot8	,c1;
	rReadP ← rTemp + 1	,c2;
	rReadV ← rReadV and ~00FF, GOTO[ReadMap]	,c3;



{
	Subroutine SaveReadPtr is called to save the current input list (bandlist or leftover list) real pointer and the
	virtual page number needed when a page-cross occurs in that list.  It saves the low half (rReadP) in uSaveReadPLow,
	the high half (rhReadP) in uSaveReadPHigh, and the virtual page number (uVirtPage) in uSaveVirtPage.
	SaveReadPtr returns through label SaveReadPtrRets via pRet2.
}

SaveReadPtr:
	uSaveReadPLow ← rReadP	,c*;
	rReadP ← rhReadP	,c*;
	uSaveReadPHigh ← rReadP	,c*;
	rReadP ← uVirtPage, pRet2	,c*;
	uSaveVirtPage ← rReadP, RET[SaveReadPtrRets]	,c*;



{
	Subroutine PageNumToPtr is called to convert the virtual page number in rTemp to a long pointer. The low word is left in rJunk, and the high byte in rTemp.  (Note that, on return, only the low eight bits of rTemp are valid.)
	PageNumToPtr returns through label PageNumToPtrRets via pRet2.
}

PageNumToPtr:
	rTemp ← rTemp LRot8, pRet2	,c*;
	rJunk ← rTemp and ~00FF, RET[PageNumToPtrRets]	,c*;

{
	Subroutine TempRot12 is called to rotate rTemp by 12. A dispatch is pending.
}

TempRot12:
	rTemp ← rTemp LRot12, DISP4[Rot12Ret]	,c*;