*----------------------------------------------------------- Title[DMesaRW...September 16, 1981 11:09 AM...Taft/Haugeland]; *----------------------------------------------------------- % CONTENTS, by order of occurence Read/write using TOS as pointer Rn Read (TOS+n) RB Read Byte Wn Write (TOS+n) WB Write Byte WS0 Write Swapped (indexed by) Zero WSB Write Swapped Byte RD0 Read Double (Indexed by) zero RDB Read Double Byte WD0 Write Double (Indexed by) zero WDB Write Double Byte WSDB Write Swapped Double Byte Read/Write field RWFAlphaBeta Subroutine supporting RF/WF (Alto-Mesa only) RF Read Field RFC Read Field Code RFS Read Field Stack WF Write Field WSF Write Swapped Field WFS Write Field Stack Read/Write string RSTR Read String WSTR Write String Read/Write indexed and indirect RXLP Read Indexed Local Pair WXLP Write Indexed Local Pair RIL0 Read Indirect Local Zero RILP Read Indirect Local Pair RIGP Read Indirect Global Pair WILP Write Indirect Local Pair Block transfers BITBLT Bit-boundary Block Transfer (Alto only) BLT Block Transfer BLTC Block Transfer Code BLTSetupTransfer Subroutine supporting Block Transfers BRgetsVA Subroutine to copy Base Register % TopLevel; * Read/Write using TOS as pointer *----------------------------------------------------------- IFUR[R0, 1, MDS, N[0]]; * Read n: p _ Pop[]+n; Push[FetchMDS[p]^]; IFUR[R1, 1, MDS, N[1]]; IFUR[R2, 1, MDS, N[2]]; IFUR[R3, 1, MDS, N[3]]; IFUR[R4, 1, MDS, N[4]]; IFUR[RB, 2, MDS]; * Read Byte: p _ Pop[]+alpha; Push[FetchMDS[p]^]; *----------------------------------------------------------- :IfMEP; T_ Stack&-1, Branch[.+2]; IFetch_ MD, IFUNext1; IFetch_ T, T_ StackNoUfl&+1, IFUNext1; :Else; IFetch_ Stack, IFUNext1; :EndIf; *----------------------------------------------------------- IFUR[W0, 1, MDS, N[0]]; * Write n: p _ Pop[]+n; StoreMDS[p]^ _ Pop[]; IFUR[W1, 1, MDS, N[1]]; IFUR[W2, 1, MDS, N[2]]; IFUR[WB, 2, MDS]; * Write Byte: p _ Pop[]+alpha; StoreMDS[p]^ _ Pop[]; *----------------------------------------------------------- T_ (ID)+(Stack&-1), Branch[WNM1]; :IfMEP; T_ (ID)+MD, Stack&-1_ MD, Branch[WNM1]; T_ (ID)+T, Branch[WNM1]; :EndIf; WNM1: * This is the tail of many "Write" opcodes Store_ T, DBuf_ Stack&-1, IFUNext0CF; *----------------------------------------------------------- IFUR[WS0, 1, MDS, N[0]]; * Write Swapped Zero: * u _ Pop[]; p _ Pop[]; StoreMDS[p]^ _ u; IFUR[WSB, 2, MDS]; * Write Swapped Byte: * u _ Pop[]; p _ Pop[]+alpha; StoreMDS[p]^ _ u; *----------------------------------------------------------- StkP-1, Branch[WSBM2]; :IfMEP; T_ (ID)+T, Stack_ MD, Branch[WSBM1]; :EndIf; WSBM2: T_ (ID)+(Stack&+1), Branch[WSBM1]; WSBM1: Store_ T, DBuf_ Stack&-2, IFUNext0CF; *----------------------------------------------------------- IFUR[RD0, 1, MDS, N[0]]; * Read Double Zero: * p _ Pop[]; u _ FetchMDS[p]^; v _ FetchMDS[p+1]^; Push[u]; Push[v]; IFUR[RDB, 2, MDS]; * Read Double Byte: * p _ Pop[]+alpha; u _ FetchMDS[p]^; v _ FetchMDS[p+1]^; Push[u]; Push[v]; *----------------------------------------------------------- T_ (IFetch_ Stack)+1, Branch[RDBM1]; :IfMEP; T_ (IFetch_ MD)+1, Branch[RDBM1]; T_ (IFetch_ T)+1, StkP+1, Branch[RDBM1]; :EndIf; * Note: IFetch did not advance the IFU pipe, so we can do it again! * Note: must not clobber stack with first word until we know the fetch of * the second word won't fault. RDBM1: IFetch_ T, T_ MD; RDBM2: Stack&+1_ T, T_ MD, Branch[PushT]; * Tail of RDBL *----------------------------------------------------------- IFUR[WD0, 1, MDS, N[0]]; * Write Double Zero: * p _ Pop[]; StoreMDS[p+1]^ _ Pop[]; StoreMDS[p]^ _ Pop[]; IFUR[WDB, 2, MDS]; * Write Double Byte: * p _ Pop[]+alpha; StoreMDS[p+1]^ _ Pop[]; StoreMDS[p]^ _ Pop[]; *----------------------------------------------------------- T_ (ID)+(Stack&-1)+1, Branch[WDBM1]; :IfMEP; T_ (ID)+MD+1, StkP-1, Branch[WDBM1]; T_ (ID)+T+1, Branch[WDBM1]; :EndIf; WDBM1: T_ (Store_ T)-1, DBuf_ Stack&-1, Branch[WNM1]; *----------------------------------------------------------- IFUR[WSDB, 2, MDS]; * Write Swapped Double Byte: * v _ Pop[]; u _ Pop[]; p _ Pop[]+alpha; StoreMDS[p+1]^ _ v; StoreMDS[p]^ _ u; *----------------------------------------------------------- RTemp0_ Stack&-2, Branch[WSDBM1]; :IfMEP; RTemp0_ MD, StkP-2, Branch[WSDBM1]; RTemp0_ T, StkP-1, Branch[WSDBM1]; :EndIf; WSDBM1: T_ (ID)+(Stack&+1)+1; T_ (Store_ T)-1, DBuf_ RTemp0; Store_ T, DBuf_ Stack&-2, IFUNext0CF; :If[AltoMode]; ********** Alto version ********** *----------------------------------------------------------- RWFAlphaBeta: * Prepares alpha and beta for RF/WF opcodes and restarts IFU if necessary. * Entry conditions: T=PCX+3, RTemp0=(PCX+2) RSH 1, MemBase=CODE. * Exit conditions: T=alpha, RTemp0=beta. *----------------------------------------------------------- Subroutine; Global, RTemp0_ T, Fetch_ RTemp0; * Fetch alpha,,beta * In the following instruction, RisID advances the IFU pipe (required for * 3-byte opcodes), but "R even" still tests RTemp0. T_ T+1, RTemp0_ MD, RisID, Branch[.+2, R even]; PCF_ T; * Restart IFU at PCX+4 T_ RSH[RTemp0, 10]; RTemp0_ (RTemp0) AND (377C), Return; * R,,R source for RF_/WF_ shift TopLevel; *----------------------------------------------------------- IFUR[RF, 3, Code, N[2]]; * Read Field * Alto Mesa: this is an aligned 3-byte instruction *----------------------------------------------------------- T_ (ID)-(PCX'), Branch[RFM1]; * T_ PCX+3 :IfMEP; T_ (ID)-(PCX'), Stack_ MD, Branch[RFM1]; T_ (ID)-(PCX'), StkP+1, Branch[RFM1]; :EndIf; RFM1: RTemp0_ (T-1) RSH 1, Call[RWFAlphaBeta]; RFM2: T_ (Stack)+T, MemBase_ MDS; * T_ pointer+alpha RFM3: T_ RTemp0, Fetch_ T; Stack_ MD, RF_ T; StackT_ ShiftLMask[StackT], IFUNext2; *----------------------------------------------------------- IFUR[RFC, 3, Code, N[2]]; * Read Field Code * Alto Mesa: this is an aligned 3-byte instruction *----------------------------------------------------------- T_ (ID)-(PCX'), Branch[RFCM1]; * T_ PCX+3 :IfMEP; T_ (ID)-(PCX'), Stack_ MD, Branch[RFCM1]; T_ (ID)-(PCX'), StkP+1, Branch[RFCM1]; :EndIf; RFCM1: RTemp0_ (T-1) RSH 1, Call[RWFAlphaBeta]; T_ (Stack)+T, Branch[RFM3]; * T_ pointer+alpha *----------------------------------------------------------- IFUR[RFS, 1, MDS, N[1]]; * Read Field Stack * Alto Mesa: this is an aligned 1-byte instruction *----------------------------------------------------------- RTemp0_ T_ Stack&-1, Branch[RFSM1]; :IfMEP; RTemp0_ T_ B_ MD, StkP-1, Branch[RFSM1]; RTemp0_ T, Branch[RFSM1]; :EndIf; RFSM1: RTemp1_ (ID)-(PCX'); * PCX+2 T_ RSH[T, 10], RTemp1, Branch[.+2, R odd]; PCF_ RTemp1; * Restart IFU at PCX+2 RTemp0_ (RTemp0) AND (377C), Branch[RFM2]; :Else; ******** PrincOps version ******** *----------------------------------------------------------- IFUR[RF, 3, MDS]; * Read Field * p _ Pop[]+alpha; Push[ReadField[FetchMDS[p]^, beta]]; *----------------------------------------------------------- IFetch_ Stack, TisID, Branch[RFM1]; :IfMEP; Stack_ MD, Branch[.-1]; StkP+1, Branch[.-2]; :EndIf; RFM1: RF_ ID, Stack_ MD; RFM2: StackT_ ShiftLMask[StackT], IFUNext2; *----------------------------------------------------------- IFUR[RFC, 3, Code]; * Read Field Code * offset _ Pop[]+alpha; Push[ReadField[Fetch[C+LONG[offset]]^, beta]]; *----------------------------------------------------------- T_ (ID)+(Stack), Branch[RFCM1]; :IfMEP; T_ (ID)+MD, Stack_ MD, Branch[RFCM1]; T_ (ID)+T, StkP+1, Branch[RFCM1]; :EndIf; RFCM1: Fetch_ T, Branch[RFM1]; *----------------------------------------------------------- IFUR[RFS, 1, MDS]; * Read Field Stack * desc: FieldDesc _ Pop[]; p _ Pop[]+desc.offset; * Push[ReadField[FetchMDS[p]^, desc.field]]; *----------------------------------------------------------- T_ RSH[Stack&-1, 10], Branch[RFSM1]; * T_ offset :IfMEP; Stack_ MD, Branch[.-1]; T_ RSH[T, 10], Branch[RFSM1]; :EndIf; RFSM1: T_ (Stack&+1)+T; * T_ pointer+offset Fetch_ T, T_ Stack&-1; RFSM2: T_ T AND (377C); * T_ desc -- must force R,,R source RF_ T, Stack_ MD, Branch[RFM2]; :EndIf; ********************************** :If[AltoMode]; ********** Alto version ********** *----------------------------------------------------------- IFUR[WF, 3, Code, N[2]]; * Write Field * Alto Mesa: this is an aligned 3-byte instruction *----------------------------------------------------------- T_ (ID)-(PCX'), Branch[WFM1]; * T_ PCX+3 :IfMEP; T_ (ID)-(PCX'), Stack_ MD, Branch[WFM1]; T_ (ID)-(PCX'), StkP+1, Branch[WFM1]; :EndIf; WFM1: RTemp0_ (T-1) RSH 1, Call[RWFAlphaBeta]; WFM2: T_ (Stack&-1)+T, MemBase_ MDS; * T_ pointer+alpha WFM3: * Enter here from WFLM Fetch_ T, RTemp1_ Stack&-1; WFM4: WF_ RTemp0; RTemp1_ ShMDBothMasks[RTemp1]; Store_ T, DBuf_ RTemp1, IFUNext0CF; *----------------------------------------------------------- IFUR[WSF, 3, Code, N[2]]; * Write Swapped Field * Alto Mesa: this is an aligned 3-byte instruction *----------------------------------------------------------- T_ (ID)-(PCX'), StkP-1, Branch[WSFM1]; * T_ PCX+3 :IfMEP; T_ (ID)-(PCX'), Stack&-1_ MD, Branch[WSFM1]; T_ (ID)-(PCX'), Branch[WSFM1]; :EndIf; WSFM1: RTemp0_ (T-1) RSH 1, Call[RWFAlphaBeta]; T_ (Stack&+1)+T, MemBase_ MDS; * T_ pointer+alpha Fetch_ T, RTemp1_ Stack&-2, Branch[WFM4]; *----------------------------------------------------------- IFUR[WFS, 1, MDS, N[1]]; * Write Field Stack * Alto Mesa: this is an aligned 1-byte instruction *----------------------------------------------------------- RTemp0_ T_ Stack&-1, Branch[WFSM1]; :IfMEP; RTemp0_ T_ B_ MD, StkP-1, Branch[WFSM1]; RTemp0_ T, Branch[WFSM1]; :EndIf; WFSM1: RTemp1_ (ID)-(PCX'); * PCX+2 T_ RSH[T, 10], RTemp1, Branch[.+2, R odd]; PCF_ RTemp1; RTemp0_ (RTemp0) AND (377C), Branch[WFM2]; :Else; ******** PrincOps version ******** *----------------------------------------------------------- IFUR[WF, 3, MDS]; * Write Field * p _ Pop[]+alpha; data _ Pop[]; * StoreMDS[p]^ _ WriteField[FetchMDS[p]^, data, beta]; *----------------------------------------------------------- T_ (IFetch_ Stack&-1)+T, TisID, Branch[WFM1]; :IfMEP; Stack_ MD, Branch[.-1]; StkP+1, Branch[.-2]; :EndIf; WFM1: WF_ ID, RTemp0_ T; WFM2: T_ ShMDBothMasks[Stack&-1]; WFM3: Store_ RTemp0, DBuf_ T, IFUNext0CF; *----------------------------------------------------------- IFUR[WSF, 3, MDS]; * Write Swapped Field * data _ Pop[]; p _ Pop[]+alpha; * StoreMDS[p]^ _ WriteField[FetchMDS[p]^, data, beta]; *----------------------------------------------------------- StkP-1, Branch[WSFM2]; :IfMEP; Stack&-1_ MD, Branch[.+1]; :EndIf; WSFM2: T_ (IFetch_ Stack&+1)+T, TisID, Branch[WSFM1]; WSFM1: WF_ ID, RTemp0_ T; T_ ShMDBothMasks[Stack&-2], Branch[WFM3]; *----------------------------------------------------------- IFUR[WFS, 1, MDS]; * Write Field Stack * desc: FieldDesc _ Pop[]; p _ Pop[]+desc.offset; data _ Pop[]; * StoreMDS[p]^ _ WriteField[FetchMDS[p]^, data, desc.field]; *----------------------------------------------------------- T_ RSH[Stack&-1, 10], Branch[WFSM1]; * T_ offset :IfMEP; Stack_ MD, Branch[.-1]; T_ RSH[T, 10], Branch[WFSM1]; :EndIf; WFSM1: RTemp0_ T_ (Stack&-1)+T; * T_ pointer+offset Fetch_ T, T_ Stack&+2; * T_ data -- so that ShC R/T select WF_ Stack&-2, Branch[WFM2]; * bits don't matter :EndIf; ********************************** *----------------------------------------------------------- IFUR[RSTR, 2, MDS]; * Read String * index _ Pop[]+alpha; p _ Pop[] + index/2; data: BytePair _ FetchMDS[p]^; * Push[IF (index MOD 2)=0 THEN data.left ELSE data.right]; *----------------------------------------------------------- * Note: the Multiply in the following instructions has the effect of, e.g.: * T_ ((ID)+(Stack&-1)) RSH 1 * and additionally the result bit shifted out is captured in Q[0]. * The operation must not generate a carry, and the Q[14] dispatch generated * as a side-effect of Multiply must be neutralized. T_ (ID)+(Stack&-1), Multiply, Branch[RSTRM1]; :IfMEP; T_ (ID)+MD, StkP-1, Multiply, Branch[RSTRM1]; T_ (ID)+T, Multiply, Branch[RSTRM1]; * T_ (index+alpha)/2 :EndIf; RSTRM1: T_ T+(Stack); RSTRM2: * Enter here from RSTRLM PD_ Q, Fetch_ T, DispTable[1, 2, 2]; * Neutralize Multiply dispatch T_ MD, Branch[.+2, ALU<0]; StackT_ RSH[T, 10], IFUNext2; * Even byte StackT_ T AND (377C), IFUNext2; * Odd byte *----------------------------------------------------------- IFUR[WSTR, 2, MDS]; * Write String * index _ Pop[]+alpha; p _ Pop[] + index/2; byte: BYTE _ Pop[]; * data: BytePair _ FetchMDS[p]^; * IF (index MOD 2) = 0 THEN data.left _ byte ELSE data.right _ byte; * StoreMDS[p]^ _ data; *----------------------------------------------------------- T_ (ID)+(Stack&-1), Multiply, Branch[WSTRM1]; :IfMEP; T_ (ID)+MD, StkP-1, Multiply, Branch[WSTRM1]; T_ (ID)+T, Multiply, Branch[WSTRM1]; * T_ (index+alpha)/2 :EndIf; WSTRM1: T_ T+(Stack&-1); WSTRM2: * Enter here from WSTRLM PD_ Q, Fetch_ T, DispTable[1, 2, 2]; * Neutralize Multiply dispatch RTemp0_ T, Branch[.+2, ALU<0]; T_ DPF[Stack&-1, 10, 10, MD], Branch[.+2]; * Even byte T_ DPF[Stack&-1, 10, 0, MD]; * Odd byte Store_ RTemp0, DBuf_ T, IFUNext0CF; * Read/Write Indexed *----------------------------------------------------------- IFUR[RXLP, 2, L, PackedAlpha]; * Read Indexed Local Pair * index _ Pop[]; p _ FetchMDS[L+alpha.left]^; * Push[FetchMDS[p+index+alpha.right]^]; *----------------------------------------------------------- T_ (ID)+(4C), Branch[RXLPM1]; :IfMEP; T_ (ID)+(4C), Stack_ MD, Branch[RXLPM1]; T_ (ID)+(4C), StkP+1, Branch[RXLPM1]; :EndIf; RXLPM1: Fetch_ T; T_ (Stack&-1)+MD, MemBase_ MDS; IFetch_ T, T_ StackNoUfl&+1, IFUNext1; *----------------------------------------------------------- IFUR[WXLP, 2, L, PackedAlpha]; * Write Indexed Local Pair * index _ Pop[]; p _ FetchMDS[L+alpha.left]^; * FetchMDS[p+index+alpha.right]^ _ Pop[]; *----------------------------------------------------------- T_ (ID)+(4C), Branch[WXLPM1]; :IfMEP; T_ (ID)+(4C), Stack_ MD, Branch[WXLPM1]; T_ (ID)+(4C), StkP+1, Branch[WXLPM1]; :EndIf; WXLPM1: Fetch_ T; T_ (ID)+(Stack&-1), MemBase_ MDS; T_ T+MD; Store_ T, DBuf_ Stack&-1, IFUNext0CF; *Read/Write Indirect *----------------------------------------------------------- IFUR[RIL0, 1, L, N[4]]; * Read Indirect Local Zero * p _ FetchMDS[L]^; Push[FetchMDS[p]^]; *----------------------------------------------------------- Fetch_ ID, Branch[RIL0M1]; :IfMEP; Fetch_ ID, Stack_ MD, Branch[RIL0M1]; Fetch_ ID, StkP+1, Branch[RIL0M1]; :EndIf; RIL0M1: MemBase_ MDS; Fetch_ MD, T_ StackNoUfl&+1, IFUNext1; *----------------------------------------------------------- IFUR[RILP, 2, L, PackedAlpha]; * Read Indirect Local Pair * p _ FetchMDS[L+alpha.left]^; Push[FetchMDS[p+alpha.right]^]; *----------------------------------------------------------- T_ (ID)+(4C), Branch[RILPM1]; :IfMEP; T_ (ID)+(4C), Stack_ MD, Branch[RILPM1]; T_ (ID)+(4C), StkP+1, Branch[RILPM1]; :EndIf; RILPM1: Fetch_ T; MemBase_ MDS; IFetch_ MD, T_ StackNoUfl&+1, IFUNext1; * Fetch_ MD+alpha[4:7] *----------------------------------------------------------- IFUR[RIGP, 2, G, PackedAlpha]; * Read Indirect Global Pair * p _ FetchMDS[G+alpha.left]^; Push[FetchMDS[p+alpha.right]^]; *----------------------------------------------------------- T_ (ID)+(3C), Branch[RILPM1]; :IfMEP; T_ (ID)+(3C), Stack_ MD, Branch[RILPM1]; T_ (ID)+(3C), StkP+1, Branch[RILPM1]; :EndIf; *----------------------------------------------------------- IFUR[WILP, 2, L, PackedAlpha]; * Write Indirect Local Pair * p _ FetchMDS[L+alpha.left]^; StoreMDS[p+alpha.right]^ _ Pop[]; *----------------------------------------------------------- T_ (ID)+(4C), Branch[WILPM1]; :IfMEP; T_ (ID)+(4C), Stack_ MD, Branch[WILPM1]; T_ (ID)+(4C), StkP+1, Branch[WILPM1]; :EndIf; WILPM1: Fetch_ T; T_ (ID)+MD, MemBase_ MDS, Branch[WNM1]; :If[AltoMode]; ********** Alto version ********** *----------------------------------------------------------- IFUR[BITBLT, 1, MDS, RBase[AEmRegs]]; * Bit-boundary block transfer * Alto Mesa: this is an aligned 1-byte instruction. *----------------------------------------------------------- ETemp0_ (ID)-(PCX'), Branch[BITBLTM1]; * ID=1, so ETemp0_ PCX+2 :IfMEP; Stack_ MD, Branch[.-1]; StkP+1, Branch[.-2]; :EndIf; BITBLTM1: ETemp0, Branch[.+2, R odd]; * ETemp0 = PCX+2 PCF_ ETemp0; * Must restart IFU due to alignment SCall[BitBltSub]; Branch[MesaReschedTrap]; * +1 return: interrupt pending StkP-2, IFUNext0; * +2 return: done :Else; ******** PrincOps version ******** * PrincOps BitBlt defined in PilotBitBlt.mc :EndIf; ********************************** *----------------------------------------------------------- IFUR[BLT, 1, MDS]; * Block Transfer: DoBLT[MDS]; IFUR[BLTC, 1, Code]; * Block Transfer Code: DoBLT[C]; * DoBLT: PROCEDURE[base: LONG POINTER] = * DO * dest: POINTER _ Pop[]; count: CARDINAL _ Pop[]; source: POINTER _ Pop[]; * IF count=0 THEN EXIT; * StoreMDS[dest]^ _ Fetch[base+LONG[source]]^; * Push[source+1]; Push[count-1]; Push[dest+1]; * IF InterruptPending[] THEN GOTO Suspend; * REPEAT Suspend => PC _ savePC; * ENDLOOP; *----------------------------------------------------------- T_ Stack&-1, Branch[BLTM2]; :IfMEP; T_ Stack&-1_ MD, Branch[BLTM2]; :EndIf; BLTM2: RTemp0_ T, DummyRef_ 0S, T_ MD, Branch[BLTM1]; * RTemp0_ dest * Copy contents of selected source BR (MDS or CODE) into BBSrcBR. BLTM1: MemBase_ BBSrcBR, Call[BRgetsVA]; * Set up BBDstBR as duplicate of MDS. MemBase_ BBDstBR; T_ A0, BRHi_ MDSHi; T_ Stack&-1, BRLo_ T; * T_ count RTemp1_ Stack&+2, Call[BLTSetupTransfer]; * RTemp1_ source * See comments under BLTSetupTransfer for how this loop works. Subroutine; BLTMLoop: MemBase_ BBSrcBR, CoReturn; Q_ RTemp0, Branch[BLTMDone, ALU=0]; Stack&-1_ Q; * Put intermediate state on stack Stack&-1_ T; T_ RTemp1; Stack&+2_ T, Branch[BLTMLoop]; TopLevel; BLTMDone: StkP-3, IFUNext0; *----------------------------------------------------------- BLTSetupTransfer: * Subroutine to handle the major work of various flavors of Block Transfer. * Does PreFetches and deals properly with interrupts and page faults. * Arranged as a coroutine pair with the caller, and coreturns once per munch * to permit the caller to copy intermediate state back onto the stack. * Thus, this routine need not know how the BLT arguments are arranged * on the stack, though it does assume that the proper way to handle an * interrupt is by initiating an immediate IFU reschedule trap. * The code is careful to touch all required memory data before altering * the intermediate state so as to work correctly in the face of page faults. * Calling sequence: * ; * ; * ; * RTemp0_ destination word address (base-relative); * RTemp1_ source word address (base-relative); * T_ word count; * Call[BLTSetupTransfer]; * Subroutine; * -- This is very important -- * Loop: MemBase_ BBSrcBR, CoReturn; * Branch[Done, ALU=0]; * MemBase = BBSrcBR * ; * Branch[Loop]; *----------------------------------------------------------- Subroutine; * Initially call here with word count in T. RTemp2_ T, MemBase_ BBDstBR; * See whether the destination address = source address +1. * The regular BLT inner loop does not handle that case correctly. DummyRef_ RTemp0, FlipMemBase, T_ MD, * Compute destination VA Branch[BLTCountZero, ALU=0]; * Branch if nothing to do RTemp3_ VALo; T_ (RTemp1)+1, Q_ VAHi; DummyRef_ T, T_ Q; * Compute source VA+1 RTemp3_ (RTemp3) XOR (VALo); * Check for resulting VAs equal T_ T XOR (VAHi); RTemp3_ (RTemp3) OR T, CoReturn; * RTemp3_ 0 iff dest = source+1 * On first coreturn, transfer ((RTemp2-1) mod 20b)+1 words. T_ (RTemp2)-1; PD_ RTemp3; * Recall which way to do the BLT T_ T AND (17C), Branch[BlkSMunchEntry, ALU=0]; * T = number of words -1 for this transfer; MemBase = BBSrcBR. * Before starting the transfer, touch the last word of the source * and destination blocks (and store into the destination), to force * any faults that would occur in mid-transfer to happen now. * Need not also touch the first word, since a fault on it will * abort the loop before it has done anything permanent. BLTMunchEntry: T_ (RTemp1)+(Q_ T), Branch[BLTInterrupt, Reschedule]; RTemp3_ (Fetch_ T)+(20C); * Fetch last source word PreFetch_ RTemp3, FlipMemBase; T_ (RTemp0)+Q; RTemp3_ (Fetch_ T)+(20C); * Fetch last destination word PreFetch_ RTemp3, RTemp3_ MD; RTemp2_ (RTemp2)-(Cnt_ Q)-1; * Update word count Store_ T, DBuf_ RTemp3, FlipMemBase; *Dirty last destination word RTemp1_ (Fetch_ RTemp1)+1, Branch[BLTMunchExit, Cnt=0&-1]; BLTWordLoop: * Inner loop: 2 instructions per word transferred. RTemp1_ (Fetch_ RTemp1)+1, T_ MD, FlipMemBase; RTemp0_ (Store_ RTemp0)+1, DBuf_ T, FlipMemBase, Branch[BLTWordLoop, Cnt#0&-1]; * BLTSetupTransfer (cont'd) BLTMunchExit: FlipMemBase; RTemp0_ (Store_ RTemp0)+1, DBuf_ MD, FlipMemBase; T_ RTemp2, CoReturn; * On each subsequent coreturn, transfer 20b words. T_ 17C, Branch[BLTMunchEntry]; * Here to handle the "destination = source+1" case. * This is implemented as a simple replication of the first source word * throughout the destination block. * T = number of words -1 for this transfer; MemBase = BBSrcBR. * First, do PreFetches for the next transfer. * (Need not touch block beforehand, since this case of BLT is idempotent.) BlkSMunchEntry: RTemp1_ T_ (Fetch_ RTemp1)+(Q_ T)+1, * Updated source ptr = last dest Branch[BlkSInterrupt, Reschedule]; RTemp3_ T+(20C), T_ MD; * T_ source word to be replicated PreFetch_ RTemp3, FlipMemBase; RTemp2_ (RTemp2)-(Cnt_ Q)-1; * Update word count BlkSWordLoop: * Inner loop: 1 instruction per word transferred. RTemp0_ (Store_ RTemp0)+1, DBuf_ T, Branch[BlkSWordLoop, Cnt#0&-1]; BlkSMunchExit: T_ RTemp2, B_ MD, FlipMemBase, CoReturn; * On each subsequent coreturn, transfer 20b words. T_ 17C, Branch[BlkSMunchEntry]; * Here if word count = 0 on entry. Force caller to quit immediately. BLTCountZero: T_ A0, CoReturn; Branch[.-1]; * Here if an interrupt is (possibly) pending. * The caller has just finished putting the intermediate state on the stack, * so all we have to do is cause a Reschedule trap and restart the IFU * at the current instruction (i.e., at the BLT). TopLevel; BLTInterrupt: RescheduleNow, Branch[.+2]; BlkSInterrupt: RescheduleNow; T_ NOT (PCX'), Branch[SetPCAndJump0]; *----------------------------------------------------------- BRgetsVA: * Subroutine to facilitate copying one base register to another. * Typical call: * MemBase_
; * DummyRef_ 0S; * MemBase_
, Call[BRgetsVA]; *----------------------------------------------------------- Subroutine; T_ VAHi; BRHi_ T; T_ VALo; BRLo_ T, Return; TopLevel; (1552)