Title[RastMain.mc.....May 23, 1989 2:30:30 pm PDT...Rumph]; Set[XTask, IP[WT]]; WTInitPC: Subroutine; DontKnowRBase; T_ WT, CoReturn; TopLevel; RBase_ RBase[RastRMForA]; MemBase_ RastBRForA; T _ TaskCmd; TIOA_ T; T_ 20C, Block; * same for all subtasks WTStart: aCount_ (aCount)-1, Branch[WTCheck, R<0]; aAddress_ (IOFetch_ aAddress)+T, Block, Branch[WTStart]; WTCheck: aAddress_ (aAddress) OR (WTBeginLineFlag), Branch[WTEndLine, R>=0]; WTBeginLine: aCount_ aNextCount; * (# Munches to Fetch)-1 T_ aNextAddrHi; PD_ T OR (aNextAddrLo); T_ 20C, Branch[WTBadWake, ALU=0]; aAddress_ (aAddress) AND (AddressMask); * mask off just channel id BrHi_ aNextAddrHi; BrLo_ aNextAddrLo, Branch[WTStart]; WTEndLine: T_ 1C; Output_ T; WTEndLineEnd: T_ 20C, Block, Branch[WTStart]; WTBadWake: BDispatch_ aAddress; RBase_ RBase[LTRegion]; * the Dispatch modifies this instruction's next address T_ LTStatus.DBadWake, Branch[WTFinishBadWake], DispTable[4]; T_ LTStatus.CBadWake, Branch[WTFinishBadWake]; T_ LTStatus.BBadWake, Branch[WTFinishBadWake]; T_ LTStatus.ABadWake; WTFinishBadWake: LTStatus_ T OR (LTStatus); T_ (WTShutUp), Call[OutputGetsT]; RBase_ RBase[RastRMForA], Branch[WTEndLineEnd]; Set[XTask, IP[LT]]; LTInitPC: Subroutine; DontKnowRBase; T_ LT, CoReturn; TopLevel; Nop; * for placement RBase_ RBase[LTRegion]; MemBase_ LTBR; T_ SelCmd; T_ A0, TIOA_ T, Call[OutputGetsT]; TIOA[DataCmd]; LTSavedCnt_ Cnt; T_ 20C; T_A0, Cnt_ T; Output_ T, Branch[., Cnt#0&-1]; TIOA[TaskCmd]; T_ RastAllShutUp, Call[OutputGetsT]; * clears SubTask LTIndexToStore_ T_ A0, Call[OutputGetsT]; * reenable the task wakeups LTStatus_ A0; * initial state LTLineState_ AllFirstTime; * first time, don't store status LTSTBLines_ T-T-1; T_ T+1; * already checked the seal T_ (Fetch_ T)+1; LTNextSTBAddrLo_ MD, T_ (Fetch_ T)+1; LTNextSTBAddrHi_ MD, T_ (Fetch_ T)+1; LTScratch_ nChannels; Cnt_ LTScratch; LTScratch_ AChannelRBase; InitChannelLoop: RBase_ LTScratch; * loaded from [14:17] KnowRBase[RastRMForA]; * but really each region in parallel aAddress_ Cnt; aAddress_ (aAddress) OR (WTBeginLineFlag); aCount_ T-T-1; aNextCount_ T-T-1; aNextAddrHi_ A0; aNextAddrLo_ A0; aNextRCBAddrLo_ MD, T_ (Fetch_ T)+1; aNextRCBAddrHi_ MD, T_ (Fetch_ T)+1; aCCRTemp_ InitialCCR; * 17000C aLineRepeatCount_ T-T-1; aRCBLineRepeatCount_ T-T-1; aLines_ T-T-1; aStatus_ (BadStatus); RBase_ RBase[LTRegion]; LTScratch_ (LTScratch)+1, Branch[InitChannelLoop, Cnt#0&-1]; LTFlags_ MD, T_ (LTStatusAddr); Store_ T, DBuf_ (0C); * reset the LT error status TaskingOff, Call[WTInitPC]; LdTPC_T, Wakeup[WT]; TaskingOn, Branch[.+2]; LTStartLine: LTSavedCnt_ Cnt; LTSavedQ_ Q; T_ (LTLineState) AND (StateMask); * check D Channel for New RCB PD_ T XOR (NewRCB); TIOA[DataCmd], Branch[LTStartLine1, ALU#0]; Output_ LTCursorCtl; * NLCB Address should be set correctly Output_ LTModeCtl; * from the last time through the scanline Output_ LTHalftoneCtl; * loop. Output_ LTSelCtl; LTStartLine1: PD_ LTSTBLines; * any lines left in this STB? T_ LTNextSTBAddrHi, Branch[LTStartLine2, ALU>=0]; PD_ (LTNextSTBAddrLo) OR (T); T_ A0, Branch[LTStartLine3, ALU=0]; BRHi_ LTNextSTBAddrHi; * need the next STB element BRLo_ LTNextSTBAddrLo; T_ (Fetch_ T)+1; LTScratch_ (GoodSTBSeal); PD_ (LTScratch) XOR (MD); T_ (Fetch_ T)+1, Branch[BadSTBSeal, ALU#0]; LTSTBLines_ MD, T_ (Fetch_ T)+1; TIOA[SelCmd]; * prepare to transfer 20b STB states to NLCB LTScratch_ (STBStateNLCB); Output_ LTScratch; TIOA[DataCmd]; LTScratch_ nStates; Cnt_ LTScratch; STBStatesLoop: Output_ MD; T_ (Fetch_ T)+1, Branch[STBStatesLoop, Cnt#0&-1]; TIOA[SelCmd]; * prepare to transfer 20b STB counts to NLCB LTScratch_ (STBCountNLCB); Output_ LTScratch; TIOA[DataCmd]; LTScratch_ nStates; Cnt_ LTScratch; STBCountsLoop: Output_ MD; T_ (Fetch_ T)+1, Branch[STBCountsLoop, Cnt#0&-1]; LTNextSTBAddrLo_ MD, Fetch_ T; LTNextSTBAddrHi_ MD; BRHi_ LTMRBAddrHi; BRLo_ LTMRBAddrLo; LTStartLine2: LTSTBLines_ (LTSTBLines)-1, Branch[LTStartLine3]; BadSTBSeal: LTStatus_ (LTStatus) OR (LTStatus.badSTBSeal); BRHi_ LTMRBAddrHi; BRLo_ LTMRBAddrLo; LTStartLine3: LTScratch_ nChannels; Cnt_ LTScratch; T_ A0, TIOA[SelCmd], Call[OutputGetsT]; * Kill the LT wakeup TIOA[DataCmd]; LTScratch_ AChannelRBase; LTChannelLoop: LTLineState_ RCy[LTLineState, LTLineState, 4]; * Get the next channel's data Q_ LTLineState; RBase_ LTScratch; * loaded from [14:17] KnowRBase[RastRMForA]; * but really parallel regions BRLo_ aNextRCBAddrLo; BRHi_ aNextRCBAddrHi; PD_ Q; Branch[LTThisLine, ALU>=0]; T_ (aStatusToStore) OR (RCBComplete); aStatusToStore_ StatusAddr; * Trick: reuse RM as temp DBuf_ T, Store_ aStatusToStore; T_ protoFinishedRCB, Call[LTPrepareNotify]; T_ ClearStoreStatus; T_ (Q) AND (T); Q_ T; LTThisLine: T_ aIndexIntoBuffer, BDispatch_ Q; LTIndexToStore_ T;* Address for BDispatch to modify Branch[LTNextLine], DispTable[5]; * case FirstTime aStatusToStore_ aStatus, Branch[LTNewLine]; * case NewRCB PD_ aStatus, Branch[LTNewLine]; * case NewLine T_ DontSwapBuffers, Branch[LTRepeatingLine]; * case RepeatingLine aCCRTemp_ aCCR, Branch[LTNextOutput]; * case InactiveChannel LTNewLine: aCCRTemp_ aCCR, DblBranch[LTNextLine, LTTurnItemOn, ALU>=0]; LTRepeatingLine: aCCRTemp_ (aCCR) OR (T); (aStatus), Branch[LTNextLine, R>=0]; LTTurnItemOn: aCCRTemp_ (aCCRTemp) OR (ItemOnThisLine); LTNextLine: T_ ClearStateMask; T_ (Q) AND (T); Q_ T, PD_ A_ aLineRepeatCount; Branch[LTNextNew, ALU<0]; T_ (T) OR (RepeatingLine); Q_ T, aLineRepeatCount_ (aLineRepeatCount)-1; Output_ aCCRTemp, Branch[LTEndScanLine]; LTNextNew: PD_ aLines; T_ (T) OR (NewLine), Branch[LTEndRCB, ALU<0]; Q_ T; aLineRepeatCount_ aRCBLineRepeatCount; aLines_ (aLines)-1; PD_ aStatus; T_ (aCCRTemp) OR (ChanWantsWT), Branch[LTNextOutput, ALU>=0]; Output_ T, T_ A_ aWordsPerLine; ANextAddrLo_ (ANextAddrLo) + (T), Branch[LTNextNewBack, ALU<0]; ANextAddrHi_ A_ ANextAddrHi, XorSavedCarry, Branch[LTEndScanline]; LTNextNewBack: ANextAddrHi_ (ANextAddrHi)-1, XorSavedCarry, Branch[LTEndScanline]; LTEndRCB: T_ (NewRCB); T_ (Q) OR (T); Q_ T; PD_ (aStatus) XOR (BadStatus); T_ (NextRCBAddrAddr), Branch[LTNextNewRCB, ALU=0]; aNextRCBAddrLo_ SetStoreStatus; aNextRCBAddrLo_ (Q) OR (aNextRCBAddrLo); * Using RM as a temp here Q_ aNextRCBAddrLo, T_ (Fetch_ T)+1; * since it's being loaded next aNextRCBAddrLo_ MD, Fetch_ T; aNextRCBAddrHi_ MD; LTNextNewRCB: T_ aNextRCBAddrLo; PD_ (aNextRCBAddrHi) OR T; T_ ClearStateMask, Branch[LTMakeInactive, ALU=0]; BRLo_ aNextRCBAddrLo; T_ A0, BRHi_ aNextRCBAddrHi; * RCBSealAddr is 0 T_ (Fetch_ T)+1; aLines_ GoodRCBSeal; * Trick: use RM as temp PD_ (MD) XOR (aLines); Branch[BadRCBSeal, ALU#0]; T_ (Fetch_ T)+1; PD_ MD; T_ (Fetch_ T)+1, Branch[LTNextNewRCB1a, ALU#0]; PD_ MD; Branch[LTNextNewRCB1, ALU#0]; T_ ClearStateMask, Branch[LTMakeInactive]; * for MicroD placement BadRCBSeal: T_ protoBadRCBSeal; * for MicroD placement Call[LTPrepareNotify]; T_ ClearStateMask; LTMakeInactive: aNextAddrHi_ A0; * so WT can check for bad wakes aNextAddrLo_ A0; T_ (Q) AND (T); T_ (T) OR (InactiveChannel); Q_ T, Branch[LTNextOutput]; LTNextNewRCB1: nop; LTNextNewRCB1a: T_ (Fetch_ T)+1; aLines_ MD, T_ (Fetch_ T)+1; aRCBLineRepeatCount_ MD, T_ (Fetch_ T)+1; aLineRepeatCount _ aRCBLineRepeatCount; aCCR_ MD, T_ (Fetch_ T)+1; PD_ aStatus_ MD; Branch[.+2, ALU<0]; * buffer pointer valid? Branch[LTNextOutput]; * for MicroD placement T_ (Fetch_ T)+1; aNextAddrLo_ MD, T_ (Fetch_ T)+1; aNextAddrHi_ MD, T_ (Fetch_ T)+1; aNextCount_ MD, T_ (Fetch_ T)+1; aWordsPerLine_ MD, T_ (Fetch_ T)+1; aIndexIntoBuffer_ MD; aCCRTemp_ (aCCRTemp) OR (ChanWantsWT); LTNextOutput: Output_ aCCRTemp; LTEndScanline: RBase_ RBase[LTRegion]; Output_ LTIndexToStore; LTLineState_ Q; LTScratch_ (LTScratch)+1, Branch[LTChannelLoop, Cnt#0&-1]; LTScratch_ LTLineState; LTScratch_ (LTScratch) AND (StateMask); PD_ (LTScratch) XOR (NewRCB); T_ CursorCtlAddr, Branch[LTEnd, ALU#0]; T_ (Fetch_ T)+1; LTCursorCtl_ MD, T_ (Fetch_ T)+1; LTModeCtl_ MD, T_ (Fetch_ T)+1; LTHalftoneCtl_ MD, Fetch_ T; LTSelCtl_ MD; LTEnd: BRHi_ LTMRBAddrHi; BRLo_ LTMRBAddrLo; T_ LTStatusAddr; T_ (Fetch_ T)-1; PD_ (LTStatus) XOR MD; * see if the status changed T_ (Fetch_ T)+1, Branch[LTEnd1, ALU=0]; * get the interrupt mask, preparing to notify Store_ T, DBuf_ LTStatus; RBase_ RBase[NWW]; NWW_ (NWW) OR MD, Reschedule; RBase_ RBase[LTRegion]; LTEnd1: Cnt_ LTSavedCnt; Q_ LTSavedQ, Block, Branch[LTStartLine]; LTPrepareNotify: Subroutine; RBase_ RBase[LTRegion]; LTScratch_ Cnt; Branch[.+2, Cnt=0&-1]; T_ LSh[T, 3], Branch[.-1]; LTStatus_ (LTStatus) XOR (T); Cnt_ LTScratch; LTScratch_ (LTScratch) XOR (AddressXOR); RBase_ LTScratch, Return; !6RastMain.mc Copyright c 1986, 1987, 1988, 1989 by Xerox Corporation. All rights reserved. Dave Rumph, May 23, 1989 2:37:19 pm PDT Main part of Dorado raster controller microcode -- included with emulators, but not included with Bootstrap/Initial microcode. Word Task (WT) microcode. This microcode is structured to use subtasks, and can run on behalf of any of A, B, C or D channels of the Raster Controller board set. The channels are differentiated by SubTask. Thus, for example, references to aCount (below) apply to aCount, bCount, cCount or dCount, depending on the what the hardware puts on SubTask. Because this code uses subtasks, it must ALWAYS Branch to the same place when blocking, must never test Branch conditions across blocks, and must use task-specific RBase, RStk, and MemBase values correctly. Note that the controller is designed to prohibit wakeups while WT is initiated (either running or preempted) and for at least n instructions after any BLOCK, where n is approximately 5. WT microcode wakes up in response to hardware flags set by the LT microcode. WT does not need to be specially awakened for initialization. WT will initialize itself EXCEPT that aAddress, bAddress, aCount, bCount, etc. must have been initialized explicitly by LT, because one cannot guarantee which subtask will run first, and WTInit is executed only once. Subtask.0 defines a block of 16 subtask specific registers, of which 5 per subtask are used by WT: aAddress, aCount, aNextCount, aNextAddrLo, and aNextAddrHi are the subtask-specific registers for Channel A. The other 11 are used by LT in a channel-specific way. There is a similar set for each other channel. Because the RM is limited and must be channel-specific, the WT code uses a few tricks to conserve RM. The discussion that follows refers to, for example, aAddress, to represent all four channels' address register (as does the actual WT code). In addition to holding the incremental munch address beyond the beginning of the scanline, aAddress encodes the channel id (3=A, 2=B, 1=C, 0=D) in the bottom two bits, which are ignored by IOFetch. Care is taken to avoid clearing those two bits at the end of a scanline. In addition, the high bit stores state. When it's on, WT has finished processing that channel's scanline shut off the hardware's wake request. It can begin processing the next line when it wakes up next. The WT microcode checks for a NIL pointer to the scanline data, and alerts the line task (LT) that an unexpected wakeup has occurred. In order to do this, WT must set one of four bits in an RM location in the LTRegion. Because the SubTask logic ORs into the address of this write, the LTRegion's bottom two address bits must already be on to avoid this nasty (in this case) effect. Raster word task initialization. Raster word task main loop -- shared by terminal word task. aCount >=0 here iff data remains to be output for the current scan line. Fetch the next munch. aAddress >= 0 if we just exhausted a scan line. aAddress < 0 if we have been awakened to start a new scan line. Starting new scan line. Check for bad wakeup, then copy parameters left by LT. The copy of aCount_ aNextCount comes before the bad wake test to prevent aCount (tested at WTStart) from beciming positive by wrapping around. Because SubTask is modifying RM addresses on the following write, LTRegion MOD 4 must = 3. Since the wrong channel is waking up, the normal loop of the WT microcode will never terminate the real requested channel. We need to shut up WT so that LT and the emulator can get back in to report the bad wake. Line Task (LT) microcode This microcode handles the full functionality needed for printer and display applications, but not FIn startup. Nor are requests to AUT to load tables yet handled. The Line Task (LT) is responsible for setting parameters in the hardware that change on a line-by-line basis. LT keeps track, for each of the four channels, of various data needed to transfer the bitmap, passing some of that information on the the Word Task (WT) as necessary. The control information neede by LT is passed to it through a data structure that begins with a Master Raster Block (MRB) which contains a seal and pointers to a State Transition Block (STB) chain, three Raster Channel Block (RCB) chains and a Control Channel Block (CCB) chain. The CCB and RCB's are nearly identical so for the remainder of this discussion, references to RCB's hold for the CCB as well. See RasterControllerFace.mesa and RasterControllerHeadDorado.mesa for the exact details about these data structures. RastLTMicrocode.mesa contains a Mesa-like implementation of this microcode for documentation purposes. Because of the design of the hardware and the interaction with the software, LT must be aware of three lines, and hence potentially three RCB's, during the same scanline. Consider the case where all scanlines are pointed to by different RCB's at an LT wakeup during the display of scanline n: The data for scanline n has finished being transferred to the hardware by WT, so the software can by told that the bitmap for scanline n is no longer needed. The scanline being transfered by WT during this LT wakeup will be displayed next line - it is scanline n+1. LT needs to load the Next Line Control Block (NLCB) with certain parameters for that line: where to start reading out of the hardware buffer RAM, whether there is data on the line, etc. LT must also pass to WT the parameters it needs to transfer line n+2, if necessary, as well as set the bit in the NLCB that wakes WT to transfer the next line. So LT needs to be aware of some aspects of line N, N+1 and N+2 during any one wakeup. During the following wakeup, LT will process more information for line N+1 and N+2 and begin N+3. To minimize the amount of data stored across that block, the order of processing is important. The microcode finishes the bookeeping for line N, sets up the parameters for line N+1 in the NLCB, leaving the control information in the RM aCCRTemp, then leaves the WT parameters in RM, sets the ChannelWantsWT bit as needed in aCCRTemp and sends it to the NLCB. It is also important to keep track, for each channel, of the state of the RCB chain. This state, the "lineState", is encoded as four bits per channel in the LTLineState word in RM. The low three bits encode the state itself, and are the index of an 8-way (nominally) BDispatch. The high bit is used as a flag to cause LT to store the status, completing the handshake with the software. The LTLineState word is right-cycled 4 bits to refer to the state information of a different channel. Since each channel uses a different RMRegion, LTLineState is stored in Q temporarily during that portion of LT's wakeup. A picture of LTLineState: --------------------------------------------------------------------------------- | A flg | D state | D flg | C state | C flg | B state | B flg | A state | | (1 bit) | (3 bits) | (1 bit) | (3 bits) | (1 bit) | (3 bits) | (1 bit) | (3 bits) | --------------------------------------------------------------------------------- This arrangement is used because the Dorado allows for easy dispatching on the low three bits and easy testing of the high bit. Raster line task initialization Zero the NLCB to prevent bad WT wakes Shut up the hardware wakeups Begin processing the MRB Initialize some parameters for this channel Initialize for WT (which can't do it itself for all four channels) Initialize some LT parameters for this channel Initialize the Word Task (WT) LT wakes up here for each scanline Finish off line N by storing the status if necessary Do the right thing depending on the line state for this channel -- dispatch on linestate (stored temporarily in Q) Start working on line N+1 If NewRCB, process CCB We need to XOR the bit in T, shifted left according to LTScratch[16:17], into LTStatus, without touching anything else. We XOR so that each transition can be noticed without the need for a handshake back from the software that the previous notify was caught. Note, however, that if the software is slow enough in responding that the microcode can change the same bit twice, the software won't see it at all. For that reason, WT ORs into the badWake bits, rather than XORs, since bad wakeups indicate hardware failure and are less well behaved in when they occur, it is much more important that the software see at least one than it know how many occurred. Κ»˜™ Icodešœ ΟmœC™NK™'—J˜˜;J™~—J˜J˜šΠbl™J™FJ™EJ™IJ™FJ™&J™J™MJ™HJ™FJ™HJ™FJ™J™J™LJ™=J™AJ™LJ™IJ™J™DJ™HJ™LJ™MJ™KJ™MJ™TJ™J™J™LJ™PJ™RJ™VJ™OJ™FJ™J™NJ™OJ™QJ™UJ™8—J˜J˜J˜šΟb ˜ J™ —J˜J˜ ˜J˜—J˜ ˜J˜J˜J˜ J˜J˜(—J˜šŸ˜J™;J™HJ˜J˜*—˜˜8J™——J˜šŸ˜J™/J™?J˜J˜C—J˜šŸ ˜ J™ίJ˜J˜,J˜J˜J˜!Jšœ(Οi˜BJ˜J˜#—J˜šŸ ˜ J˜J˜ —šŸ ˜ J˜—J˜šŸ ˜ J˜Jšœ 7˜OJ˜J˜—™J˜+J˜J˜%J˜%J˜J˜J˜JšŸ˜™+J˜-J˜?—™BJ˜J˜*J˜J˜J˜J˜J˜$J˜$—™.J˜"J˜J˜J˜J˜J˜J˜<——™J˜J˜7J˜J˜J˜—šŸ ˜ J™"J˜J˜ J˜AJ˜J˜+J˜AJ˜BJ˜#J˜—šŸ ˜ J˜4J˜1J˜Jšœ#˜#J˜7J˜J˜J˜J˜J˜+J˜ J˜J˜BJ˜J˜J˜J˜J˜—šŸ˜J˜ J˜1J˜J˜BJ˜J˜J˜J˜J˜—šŸ˜J˜ J˜1J˜J˜J˜J˜J˜—šŸ ˜ J˜1—šŸ ˜ J˜.J˜J˜—defaultšŸ ˜ J˜J˜J˜J˜—šŸ ˜ J˜