{ 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*;