:TITLE[Display]; *Definitions for Alto-compatible UTVFC *Registers and constants used by UTVFC task SETTASK[DpTask]; *Output Registers SET[vCReg,0]; *Control register SET[vBufStart,1]; *Buffer Starting Address SET[vHCRam,2]; *Horizontal control ram SET[vLdIAR,3]; *IAR[0:5] _ Start[0:5] (data is ignored) SET[vCursor0,4]; *Channel 0 Cursor control register SET[vCursor1,5]; *Channel 1 Cursor control register SET[vCursorMem0,6]; *Channel 0 Cursor Memory SET[vCursorMem1,7]; *Channel 1 Cursor Memory SET[vBuf0,10]; *Channel 0 data buffer - use with Output SET[vfBuf0,ADD[LSHIFT[DpTask,4],10]]; *Channel 0 data buffer - use with IOFetch SET[vBuf1,11]; *Channel 1 data buffer SET[vfBuf1,ADD[LSHIFT[DpTask,4],11]]; SET[vBuf2,12]; *Channel 2 data buffer SET[vfBuf2,ADD[LSHIFT[DpTask,4],12]]; SET[vBuf3,13]; *Channel 3 data buffer SET[vfBuf3,ADD[LSHIFT[DpTask,4],13]]; SET[vRB,LSHIFT[AND[DpTask,3],4]]; *enforces register allocation conventions RV[vDBuf0,ADD[vRB,0]]; *doubleword data buffer RV[vDBuf1,ADD[vRB,1]]; RV[vDBA,ADD[vRB,2]]; *used when picking up a DCB RV[vSize, ADD[vRB,2]]; *used when transmitting a DCB RV[vSLC,ADD[vRB,3]]; RV[vBase,ADD[vRB,4]]; RV[vBase1,ADD[vRB,5]]; RV[VCR,ADD[vRB,6]]; *Copy of hardware control register RV[vCursorY,ADD[vRB,7]]; RV[vTemp,ADD[vRB,10]]; RV[vCurrentY,ADD[vRB,11]]; *Current display Y RV[vCursorControl,ADD[vRB,12]]; RV[vMsg,ADD[vRB,13]]; RV[vLink,ADD[vRB,14]]; *holds DCB link word RV[vNWrds,ADD[vRB,15]]; RV[vCnt,ADD[vRB,16]]; *NOTE: because this register must be different from vMDS, *the display cannot run at Task 3 mod 4. RV[vZero,ADD[vRB,17]]; *Register containing zero RV[vMDS,76]; *base register containing 400b RV[vMDShi,77]; *base register containing MDShi MC[vMaxYh, 400]; *number of visible scan lines per field/2 -1 MC[vMaxYl, 223]; MC[vBlankLength,104]; * 2* vertical blanking time in scan lines (field A's time is increased by 1) MC[fAVSStart,77]; MC[fBVSStart,100]; MC[vSyncLength,40]; SET[msgTable,ADD[lshift[DisplayPage,10],20]]; SET[IZTab,ADD[lshift[DisplayPage,10],40]]; *dispatch table for initial zeros SET[FZTab,ADD[lshift[DisplayPage,10],60]]; *dispatch table for final zeros SET[FZTab2,ADD[lshift[DisplayPage,10],100]]; *secondary dispatch table for final zeros *Initialization for UTVFC SETTASK[DpTask]; ONPAGE[DisplayInitPage]; *Get here from DeviceInit. We are running at the display's task level. displayinit: vMDS _ 177000c, AT[DisplayInitLoc]; vCR _ 0c; Output[vCR,vCursor0]; *Disable the cursor vMDShi _ 0c; *is this done somewhere else? if so, it can be removed vMDS _ (vMDS) or (31c); *set 177037-177030 to -1 vSLC _ T _ 6c; vCR _ (zero) -1; dlcloop: nop; PStore1[vMDS,vCR]; vSLC _ T _ (vSLC) -1, goto[dlcloop,R>=0]; vCR _ 1c; Output[vCR,vCReg]; *Clear the Nibble counter vCR _ 200c; *Increment NClk bit vSLC _ 104400c; *Start _ 9d (nibble 36d), ForceAARLoad' _ 0 Output[vSLC,vBufStart], call[NClk]; *Generate NClk to load AAR vSLC _ 0c; Output[vSLC,vHCRam], call[NClk]; *HCRam[36d] _ 0. NClk does HCReg _ 0, AAR_9d. vSLC _ 55000c; vMDS _ 400c; *Initialization Output[vSLC,vBufStart]; *Clear ForceAARLoad, set ForceIARLoad, Start _ 26d (= 64 - 38) Output[vSLC,vLdIAR]; *initialize IAR vSLC _ 155000c; Output[vSLC,vBufStart]; *Clear ForceAARLoad, ForceIARLoad vDBA _ 44c; *Now we can load the entire ram, starting at location 36d. vSLC _ 0c; T _ 272c, call[OutNClk]; *Load pattern in vSLC until address = value in T vSLC _ 1c; T _ 273c, call[OutNClk]; *172d vSLC _ 0c; T _ 376c, call[OutNClk]; *254d vSLC _ 10c; T _ 377c, call[OutNClk]; *255d vSLC _ 0c; T _ 4c, call[OutNClk]; vSLC _ 4c; T _ 36c, call[OutNClk]; vSLC _ 0c; T _ 44c, call[OutNClk]; *36d vSLC _ 2c; T _ 45c, call[OutNClk]; *37d vSLC _ 0c; *set up to clear Cursor memory vCR _ 22c; *Allow display wakeups, set blanking Output[vCR,vCReg]; vZero _ 0c, call[vRet]; InitCLoad: *First wakeup comes here. Clear the cursor memory (requires 32 scan line times, 8 nibbles/line). vTemp _ 6c; ICLoop: Output[vSLC,vCursor0]; *Send address vSLC _ (vSLC) + (4c); Output[vZero, vCursorMem0]; *Send data (zero) vTemp _ (vTemp) - 1,IOStrobe, goto[ICLoop, R>=0]; vSLC _ (vSLC) + (4000c); vSLC _ (vSLC) and (174000c), goto[.+2, carry]; vRet: return; loadpage[DisplayPage]; vCurrentY _ 1c,gotop[vFirstWakeup]; *SUBROUTINE NClk generates one NClk. NClk: nop; *let the caller's R write occur Output[vCR,vCReg]; *four outputs generate one NClk Output[vCR,vCReg]; Output[vCR,vCReg]; Output[vCR,vCReg]; usectask, goto[Vret]; *SUBROUTINE OutNClk sends the pattern in vSLC to the HCRam until the address = T. OutNClk: Output[vSLC, vHCRam]; Output[vCR,vCReg]; Output[vCR,vCReg]; Output[vCR,vCReg]; Output[vCR,vCReg]; vDBA _ (vDBA)+1; vDBA _ (vDBA) and (377c); lu _ (vDBA) xor (T); goto[OutNClk, ALU#0], usectask; return; *Task microcode for Alto-compatible UTVFC SETTASK[DpTask]; ONPAGE[DisplayPage]; *Get here when the current DCB is exhausted. A branch on vCurrentY is pending. *vChkMsg has been called, and IOStrobe has been sent to the controller. GetNextDCB: T _(vLink) - (376c), goto[FieldDoneA, ALU=0]; *Testing vCurrentY *Enter here from StartFrame GetNextDCBx: PFetch2[vMDS,vDBA]; *spurious fetch from location 2 if vLink=0 lu _ vLink; T _ (vLink) - (400c), goto[GotAnotherDCB, ALU#0]; vSLC _ vSLC; *interlock vSLC _ (10000c), call[vMsgRet]; goto[WidthZero]; GotAnotherDCB: PFetch2[vMDS, vLink]; vSLC _ (vSLC) - 1, goto[LongDCB, R<0]; *bias the scan line count T _ vDBA; vBase _ T, TASK; T _ vMDShi; *Set up high base register vBase1 _ T; ChkBkgnd: lu _ ldf[vNWrds,1,1]; lu _ ldf[vCR,15,1],dblgoto[vBB,vWB,ALU#0]; *Field bit LongDCB: T _ (RSH[vMDS,6]) + (T); *Point at long pointer (-400), T_ 4+T PFetch2[vMDS,vBase], TASK; *Fetch long ptr vSLC _ (vSLC) XOR (100000c); *Turn off long DCB flag T _ (vBase1) AND (377c); *Fix up long pointer T _ vBase1_ (LSH[vBase1,10]) + (T) + 1; vBase1 _ (FixVa[vBase1]) OR (T) , goto[ChkBkgnd]; vBB: vCR _ (vCR) or (100c), dblgoto[OddField,EvenField,ALU#0]; vWB: vCR _ (vCR) and not (100c), dblgoto[OddField,EvenField,ALU#0]; OddField: lu _ ldf[vNWrds,10,10], goto[EvF1]; *Data is sent from the base of the block EvenField: T _ ldf[vNWrds,10,10]; *Data is sent starting NWrds into the block * vBase _ (vBase) + (T), FreezeResult; vBase _ (vBase) + (T), goto[OddField]; *previous instruction is replaced with this one.. EvF1: T _ ldf[vNWrds,3,5], goto[WidthNonZero,ALU#0]; *check tab count % Here, we will calculate some quantities that will be useful to the main loop. They are: vNWrds: TYPE = MACHINE DEPENDENT RECORD [ TabCountIsZero: [0..1], --means TabCount is uninteresting fill: [0..3], --unused bits TabCount: [0..37B], --number of zeros to send before sending memory data BaseAdjust: [0..377B], --number of words to add to vBase to get to the start of the next scan line's bitmap. Not used if DCB.Width = 0. This quantity will usually be DCB.Width, unless the total number of words specified by the user exceeds 38d, in which case it will be reduced. ]; vSize: TYPE = MACHINE DEPENDENT RECORD [ FinalFillIsZero: [0..1], --means FinalFill is uninteresting fill: [0..1], --unused FinalFill: [0..77B], --number of zeros to fill out the scan line DataCount: [0..177B], --number of doublewords to send to the controller from bitmap ZeroWidthDCB: [0..1], --flag bit indicating that no data is to be sent from memory. See below ]; A zero-width DCB is a special case. We set ZeroWidthDCB _ 1, DataCount _ 3, FinalFill _ 46B. Also, TabCountIsZero _ 1, TabCount _ 0, BaseAdjust _ 0. The main loop will send two scan lines of zeros (to fill the two ping-pong buffers),then stop sending data to the controller until the next DCB. % WidthZero: vSize _ 3c; vSize _ (vSize) or (23000c); Output[vCR,vCReg]; *Load the control register vNWrds _ 100000c, goto[PreDS]; WidthNonZero: vSize _ 46c, goto[TabNonZero,ALU#0]; TabZero: vNWrds _ (vNWrds) or (100000c); *Set the TabZero flag T _ rhmask[vNWrds], goto[SetUpSize]; *Want to send this many words TabNonZero: T _ (rhmask[vNWrds]) + (T); *Want to send this many words vNWrds _ (vNWrds) and not (100000c); *clear bit 0 in case the user said half resolution SetUpSize: vSize _ (vSize) - (T); *subtract desired number of words from 46b T _ rhmask[vNWrds], goto[ScanOvf, ALU<0]; *check for fit vSize _ (lsh[vSize,10]) or (T), goto[EndSize]; *it fits ScanOvf: vSize _ (vSize) + (T), goto[vSizeEven, REven]; *vSize _ (46b - TabCount) vSize _ (vSize) + (400c); *One final zero if TabCount is odd vSize _ (vSize) and not (1c); *force vSize to be even vSizeEven: vNWrds _ (vNWrds) + (T); *vNWrds[10:17] _ 2*NWrds T _ (vSize) and (376c); vNWrds _ (vNWrds) - (T), goto[EndSize]; *At this point, vNWrds has TabCount in bits 3-7 , bit 0 is set if TabCount = 0. *vNWrds[10:17] contains the amount that must be added to vBase at the end of *a scan line to get to the start of the next scan's data. If no overflow *occurred, this is just the original value. On overflow, it is *NWrds + (Nwrds - (46b - TabCount)), i.e. *NWrds + (Amount we should have sent - (Amount actually sent)) EndSize: lu _ lhmask[vSize]; *check for final fill count = 0 Output[vCR,vCReg], skip[ALU#0]; *load the control register vSize _ (vSize) or (100000c); *Set FinalFillIsZero T _ 177000c, call[vMsgRet]; *displacement for Initial zero memory references dispatch[vNWrds,4,4], dblgoto[LineWake2,LineWake1,R<0]; *Get here from end of scan line processing. NoCursor: vSLC _ (vSLC) - 1; NoCursor1: IOStrobe, vCurrentY _ (vCurrentY) - 1, goto[GetNextDCB, alu<0]; T _ rhmask[vNWrds], goto[FieldDone, alu=0]; vBase _ (vBase) + (T), call[CheckBankCross]; *Wake up here at the start of all scan lines of a DCB after the first. LineWake: dispatch[vNWrds,4,4], skip[R<0]; LineWake1: disp[IZ00]; *Tab if necessary LineWake2: T _ (vSize) and (376c), goto[SendFromMem,Reven]; ZeroWidthLine: vSize _ (vSize) - (2c), skip[ALU=0]; PreDS: T _ 177000c, goto[DataSent]; *send zeros to the controller vSize _ 1c, goto[CallChkMsg]; *The two scan lines of zeros have been sent *Dispatch Table for initial zero memory references. IZ00: IOFetch16[vMDS,vfBuf0], goto[LineWake2], AT[IZTab,00]; IZ01: Output[vZero,vBuf0], goto[ICheck16], AT[IZTab,01]; IZ02: Output[vZero,vBuf0], goto[IZ01], AT[IZTab,02]; IZ03: Output[vZero,vBuf0], goto[IZ02], AT[IZTab,03]; IZ04: IOFetch4[vMDS,vfBuf0], goto[ICheck16], AT[IZTab,04]; IZ05: IOFetch4[vMDS,vfBuf0], goto[IZ01], AT[IZTab,05]; IZ06: IOFetch4[vMDS,vfBuf0], goto[IZ02], AT[IZTab,06]; IZ07: IOFetch4[vMDS,vfBuf0], goto[IZ03], AT[IZTab,07]; IZ10: IOFetch4[vMDS,vfBuf0], goto[IZ04], AT[IZTab,10]; IZ11: IOFetch4[vMDS,vfBuf0], goto[IZ05], AT[IZTab,11]; IZ12: IOFetch4[vMDS,vfBuf0], goto[IZ06], AT[IZTab,12]; IZ13: IOFetch4[vMDS,vfBuf0], goto[IZ07], AT[IZTab,13]; IZ14: IOFetch4[vMDS,vfBuf0], goto[IZ10], AT[IZTab,14]; IZ15: IOFetch4[vMDS,vfBuf0], goto[IZ11], AT[IZTab,15]; IZ16: IOFetch4[vMDS,vfBuf0], goto[IZ12], AT[IZTab,16]; IZ17: IOFetch4[vMDS,vfBuf0], goto[IZ13], AT[IZTab,17]; ICheck16: lu _ ldf[vNWrds,3,1]; *there may be one 16-word block remaining skip[alu=0]; IOFetch16[vMDS, vfBuf0]; T _ (vSize) and (376c), goto[SendFromMem]; *Start of transmission of data from memory. *T has the number of words to send (known to be even and nonzero). SendFromMem: vCnt _ T; lu _ ldf[vBase,16,1]; *check for doubleword required lu _ ldf[vBase,14,2], goto[NLQuads, alu=0]; PFetch2[vBase,vDBuf0,0]; vBase _ (vBase) + (2c); vCnt _ (vCnt) - (2c); Output[vDBuf0, vBuf0]; Output[vDBuf1, vBuf0]; NLQ1: lu _ ldf[vBase,14,2]; NLQuads: vCnt _ (vCnt) - (4c), goto[NLHex, alu=0]; skip[alu>=0]; PFetch2[vBase,vDBuf0,0], goto[NL4]; *0 or 2 words to go IOFetch4[vBase,vfBuf0,0]; vBase _ (vBase) + (4c), goto[NLQ1]; *At NLHex, vCnt has been predecremented by 4 NLHex: vCnt _ (vCnt) - (14c), skip[R>=0]; PFetch2[vBase,vDBuf0,0], goto[NL4]; *0 or 2 words to go vCnt _ (vCnt) - (4c), skip[alu>=0]; NLHx: IOFetch4[vBase,vfBuf0,0], goto[NL16]; *4 - 14d words to go IOFetch16[vBase,vfBuf0,0]; * lu _ (vSLC) - 1; *Test for last line of DCB, task if not. * skip[ALU<0]; * call[vMsgRet]; vBase _ (vBase) + (20c), goto[NLHex]; NL4: nop; *wait for vCnt write lu _ ldf[vCnt,16,1]; *test for doubleword required NL4x: T _ 177000c, skip[ALU#0]; dispatch[vSize,4,4], dblgoto[CallChkMsg, SendFinalFill, R<0]; Output[vDBuf0, vBuf0]; vBase _ (vBase) + (2c); Output[vDBuf1, vBuf0], goto[DataSent]; *Less than 16 words to go. The first quadword is on the way, vCnt is correct. NL16: vBase _ (vBase) + (4c); lu _ ldf[vCnt,14,2]; vCnt _ (vCnt) - (4c), skip[ALU#0]; PFetch2[vBase, vDBuf0,0], goto[NL4]; IOFetch4[vBase, vfBuf0, 0], goto[NL16]; DataSent: dispatch[vSize,4,4], skip[R<0]; *dispatch on low 4 bits of FinalFill SendFinalFill: dispatch[vSize,2,2], disp[FZ00]; *Send final scan line fill, dispatch on hexes. CallChkMsg: Input[vTemp,0], call[vChkMsg]; vCursorY _ (vCursorY) + (2c), dblgoto[NoCursor, ShowCursor,R<0]; *Dispatch Table for final zero memory references. FZ00: disp[FZH0], AT[FZTab,00]; FZ01: Output[vZero,vBuf0], goto[FZCheck16], AT[FZTab,01]; FZ02: Output[vZero,vBuf0], goto[FZ01], AT[FZTab,02]; FZ03: Output[vZero,vBuf0], goto[FZ02], AT[FZTab,03]; FZ04: IOFetch4[vMDS,vfBuf0], goto[FZCheck16], AT[FZTab,04]; FZ05: IOFetch4[vMDS,vfBuf0], goto[FZ01], AT[FZTab,05]; FZ06: IOFetch4[vMDS,vfBuf0], goto[FZ02], AT[FZTab,06]; FZ07: IOFetch4[vMDS,vfBuf0], goto[FZ03], AT[FZTab,07]; FZ10: IOFetch4[vMDS,vfBuf0], goto[FZ04], AT[FZTab,10]; FZ11: IOFetch4[vMDS,vfBuf0], goto[FZ05], AT[FZTab,11]; FZ12: IOFetch4[vMDS,vfBuf0], goto[FZ06], AT[FZTab,12]; FZ13: IOFetch4[vMDS,vfBuf0], goto[FZ07], AT[FZTab,13]; FZ14: IOFetch4[vMDS,vfBuf0], goto[FZ10], AT[FZTab,14]; FZ15: IOFetch4[vMDS,vfBuf0], goto[FZ11], AT[FZTab,15]; FZ16: IOFetch4[vMDS,vfBuf0], goto[FZ12], AT[FZTab,16]; FZ17: IOFetch4[vMDS,vfBuf0], goto[FZ13], AT[FZTab,17]; FZCheck16: dispatch[vSize,2,2], goto[FZ00]; FZH0: goto[CallChkMsg], AT[FZTab2,0]; FZH1: IOFetch16[vMDS,vfBuf0], goto[CallChkMsg], AT[FZTab2,1]; FZH2: IOFetch16[vMDS,vfBuf0], goto[FZH1], AT[FZTab2,2]; ShowCursor: Output[vCursorControl, vCursor0]; *Output previously calculated control word to CReg. T _ (vCursorControl) + (10000c); *set up control word for next scan line. goto[CursorDone, Carry], lu _ (vCursorControl) and (2000c); *Check CEnable bit vCursorControl _ T, goto[NoCursor]; *Get here when the control word for the last cursor scan line has been sent, and also during the *following scan line. First, turn off the enable bit, then fix Y so that the test for cursor active *will fail for the rest of the field. CursorDone: vCursorControl _ (vCursorControl) and not (2000c), skip[ALU#0]; vCursorY _ 100000c; *Y will remain negative until EOF vSLC _ (vSLC) -1, goto[NoCursor1]; FieldDone: vSLC _ 104000c, goto[FDAx]; *set up to load cursor memory *The constant 104000 is chosen with fiendish cleverness. The first time through *LdCursMr, the load portion will be skipped. Subsequent calls will do the load *until the vSLC becomes less than 4000. We must skip the first one, because it *is not possible to load the cursor memory until pBlank is 1. FieldDoneA: vSLC _ 104000c; FDAx: T _ (vCR) and (4c); *OddField bit vCR _ (vCR) xor (4c), dblgoto[FieldA, FieldB, ALU#0]; *Complement it, test field. FieldA: vCurrentY _ (vCurrentY) - (vBlankLength) -1; *about to do odd scan lines TASK, vCursorY _ 2c; vCursorControl _ 4000c; vDBA _ fAVSStart, goto[vStartVBlank]; FieldB: vCurrentY _ (vCurrentY) - (vBlankLength); *about to do even scan lines TASK, vCursorY _ 1c; vCursorControl _ 0c; vDBA _ fBVSStart; vStartVBlank: vCR _ (vCR) or (20c), call[LdCursMr]; *ppBlank bit VSyncWait: vCurrentY _ T _ (vCurrentY) + (2c); *Wait here for time to start vsync lu _ (vDBA) + (T); *set up to resync IAR (returns to vSyncWait) vNWrds _ 55000c, dblgoto[StartVsync,LdCursM,ALU=0]; StartVsync: vCR _ (vCR) or (10c); *ppVS bit vDBA _ (vDBA) - (vSyncLength), call[LdCursMr]; InVSync: vCurrentY _ T _ (vCurrentY) + (2c); *Wait here to end vSync lu _ (vDBA) + (T); Output[vNWrds,vBufStart], goto[EndVSync,ALU=0]; *Load 55000 into START (many times) Output[vZero,vLdIAR], goto[LdCursM]; *Load IAR (returns to InVSync) EndVSync: vCR _ (vCR) and not (10c); vNWrds _ 155000c, call[LdCursMr]; *Turn off ForceIARLoad BlankWait: vCurrentY _ (vCurrentY) + (2c); *Wait here to end vBlank Output[vNWrds,vBufStart], goto[StartFrame, ALU>=0]; *Load START again (over and over) goto[LdCursM]; *returns to BlankWait StartFrame: vCurrentY _ vMaxYh; vCurrentY _ (vCurrentY) + (vMaxYl); vFirstWakeup: SetUpCursor: T _ 26c; PFetch2[vMDS,vDBuf0]; *Fetch Cursor x and y from 426b and 427b T _ (20c); vCR _ (vCR) and not (20c); *clear ppblank PFetch2[vMDS,vLink]; *Fetch chain head and interruput word. T _ vDBuf1, skip[Reven]; *Y coordinate *Y odd => invert earlier decision on which scan line of the cursor goes first. vCursorControl _ (vCursorControl) xor (4000c); vCursorY _ (vCursorY) -(T) -1; Input[vTemp,0]; *input to set up IAddr.6..7 for vChkMsg vDBuf0 _ (vDBuf0) xnor (0c); *vDBuf0 _ X' vDBuf0 _ (vDBuf0) + (4c); *increment in nibble number T _ (vDBuf0) and not (176000c); *save low ten bits vCursorControl _ (vCursorControl) + (T), call[vChkMsg]; *add X to initial Y vCursorControl _ (vCursorControl) or (2000c); *Set CEnable bit LoadPage[0]; IOStrobe, T _ vNWrds, callp[DoTIntNT]; *cause field interrupt (bits are in T, no tasking) T _ (vLink) - (376c), goto[GetNextDCBx]; *SUBROUTINE LdCursM loads one word of the cursor memory, then goes to vChkMsg. LdCursMr: usectask; T _ APC&APCTask; vBase _ T; *save return link LdCursM: vSLC _ (vSLC) - (4000c); vSLC _ (vSLC) and (174000c), skip[ALU>=0]; Output[vCR,vCReg], goto[vLDnA]; T _ (31c); T _ (ldf[vSLC,1,4]) + (T); *select the word to load Pfetch1[vMDS,vDBuf0]; *fetch it vTemp _ 2c; LoadLp: Output[vSLC,vCursor0]; *output the address (nibble 0 first) vDBuf0 _ lcy[vDBuf0,4], call[vMsgRet]; Output[vDBuf0,vCursorMem0]; *output the data vSLC _ (vSLC) + (4c); vTemp _ (vTemp) - 1, goto[LoadLp,R>=0]; vLoadDone: Output[vCR,vCReg]; *set IAddr.6,7 vLDnA: IOStrobe, call[vChkMsg]; APC&APCTask _ vBase, goto[vMsgRet]; *SUBROUTINE vChkMsg checks for and posts incoming messages. vChkMsg: vDBuf0 _ 176400c, dblgoto[vM1,vM0,NoAtten]; vM0: T _ vMsg _ (lsh[vMsg,1]), dblgoto[msgAct,vMsgRet, R<0]; vM1: vCR _ (vCR) + (4000c); *increment the message's 1's count. T _ vMsg _ (lsh[vMsg,1]) + 1, dblgoto[msgAct,vMsgRet, R<0]; vMsgRet: return; msgAct: dispatch[vCR,5,3]; *dispatch on message type bits vTemp _ T, disp[msgType0]; msgType0: T _ (ldf[vMsg,0,3]) + 1, AT[msgTable,0]; *vMsg contains the type in bits 0-3 at this time vCR _ (lcy[vCR,10]) or (T); *vCR[5..7] _ type bits vCR _ rcy[vCR,10]; vMsg _ (vMsg) and not (176000c); *clear type bits in vMsg vMsg _ (vMsg) or (1000c), return; *or in new flag bit msgType1: T _ (vDBuf0) + (34c), goto[StoreKBn], AT[msgTable,1]; *KB0 msgType2: T _ (vDBuf0) + (35c), goto[StoreKBn], AT[msgTable,2]; *KB1 msgType3: T _ (vDBuf0) + (36c), goto[StoreKBn], AT[msgTable,3]; *KB2 msgType4: T _ (vDBuf0) + (37c), goto[StoreKBn], AT[msgTable,4]; *KB3 msgType5: T _ (vDBuf0) + (30c), goto[StoreKB4], AT[msgTable,5]; *KSMS (keyset/mouse switches) StoreKB4: PStore4[vMDS,vTemp], goto[StoreKBnx]; *Stores KSMS in 177030 and 177033, junk in other 2 regs. StoreKBn: *ignore the message if it contains fewer than eight 1's. lu _ (vCR) + (140000c); *carries if count >= 8d vCR _ (vCR) and not (177400c), goto[MsgXit,NoCarry]; PStore1[vMDS,vTemp], goto[MsgXit]; StoreKBnx: vCR _ (vCR) and not (177400c); *clear type and count bits in vCR MsgXit: vMsg _ 0c, return; *This will cause a long abort when KSMS is stored. msgType6: T _ (24c), AT[msgTable,6]; PFetch2[vMDS,vDBuf0]; *MouseX,Y from 424b, 425b vTemp _ rcy[vTemp,10]; *setup for later extraction of deltaY vMsg _ T _ rsh[vMsg,10], goto[.+2, R>=0]; *extract deltaX T _ (vMsg) or (177400c); *sign extend vDBuf0 _ (vDBuf0) + (T); *add to current X vTemp _ T _ (rsh[vTemp,10]), goto[.+2, R>=0]; *extract deltaY T _ (vTemp) or (177400c); *sign extend vDBuf1 _ (vDBuf1) + (T); *add to current Y T _ (24c); PStore2[vMDS,vDBuf0], goto[StoreKBnx]; *restore X,Y msgType7: goto[StoreKBnx], AT[msgTable,7]; *no message of this type *SUBROUTINE CheckBankCross increments vBase1 if a bank boundary is crossed. *called only from LineWake-1. CheckBankCross: T _ 177000c, skip[Carry]; *displacement for Initial Zero memory refs. return; vBase1 _ (vBase1) + (400c) + 1, return; :END[Display]; (1792)