*-----------------------------------------------------------
Title[DMesaRW...September 16, 1981 11:09 AM...Taft/Haugeland];
*-----------------------------------------------------------
%

CONTENTS, by order of occurence

Read/write using TOS as pointer
RnRead (TOS+n)
RBRead Byte
WnWrite (TOS+n)
WBWrite Byte
WS0Write Swapped (indexed by) Zero
WSBWrite Swapped Byte
RD0Read Double (Indexed by) zero
RDBRead Double Byte
WD0Write Double (Indexed by) zero
WDBWrite Double Byte
WSDBWrite Swapped Double Byte

Read/Write field
RWFAlphaBetaSubroutine supporting RF/WF (Alto-Mesa only)
RFRead Field
RFCRead Field Code
RFSRead Field Stack
WFWrite Field
WSFWrite Swapped Field
WFSWrite Field Stack

Read/Write string
RSTRRead String
WSTRWrite String

Read/Write indexed and indirect
RXLPRead Indexed Local Pair
WXLPWrite Indexed Local Pair
RIL0Read Indirect Local Zero
RILPRead Indirect Local Pair
RIGPRead Indirect Global Pair
WILPWrite Indirect Local Pair

Block transfers
BITBLTBit-boundary Block Transfer (Alto only)
BLTBlock Transfer
BLTCBlock Transfer Code
BLTSetupTransfer Subroutine supporting Block Transfers
BRgetsVASubroutine 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:
*
<Pop arguments off stack>;
*
<BBDstBR← destination base pointer>;
*
<BBSrcBR← source base pointer>;
*
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
*
<Push intermediate state from RTemp0, RTemp1, and T back onto stack>;
*
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← <BR to be copied from>;
*
DummyRef← 0S;
*
MemBase← <BR to be copied into>, Call[BRgetsVA];
*-----------------------------------------------------------
Subroutine;

T← VAHi;
BRHi← T;
T← VALo;
BRLo← T, Return;

TopLevel;