:IF[AltoMode];
TITLE[MesaLS.Alto.Mode];
:ELSEIF[CedarMode];
TITLE[MesaLS.Cedar.Mode];
:ELSE;
TITLE[MesaLS.Pilot.Mode];
:ENDIF;

%
Edit by Ed Fiala 27 January 1982: Eliminate bypass kludge at LocalLP and
GlobalLP saving 2 mi; make AssignRef and AssignRefNew traps like other
undefined opcodes if WithGarbCollect false.
Edit by Ed Fiala 25 September 1981 WithGarbCollect conditional; improve and
fix bug in BackPC; bum 4 mi; replicate PUSH to avoid jumping to opcode
entry; move MIPendx here from MesaX bumming 6 mi.
Edit by Ed Fiala 30 March 1981 Fix bug in RD0 and RDB in which a page fault
occurs on the 1st of two words pushed onto the stack but not on the second.
Edit by Ed Fiala 23 March 1981 Cedar conditional for traps; move MesaBoot
from here to Initialize; improve LocalLP/GlobalLP and LPPointer/GPPointer
by 5 mi.
Edit by Jim Frandeen February 25, 1981 3:18 PM Fix stack errors in Read String Long.
Edit by Jim Frandeen January 14, 1981 11:34 AM: Add StackLPy label for checksum.
Edit by Ron Joiner December 5, 1980 3:36 PM move Page0 stuff to opPage3
Edit by Jim Frandeen December 10, 1980 4:04 PM: Fix RXLPL and WXLPL to
check for carry instead of overflow.
Edit by Jim Frandeen October 29, 1980 10:30 AM: Fix RDBL to wait for fault
before updating stack.
Edit by Johnsson September 29, 1980 8:44 AM; trap fixup
Edit by Jim Frandeen August 22, 1980 8:38 AM: TickCount is called prTime
with new Psb format.
Edit by Fiala August 19, 1980 1:42 PM Merge in Alto Mesa improvements made
since September 1979: optional cache of Locals 0 - 3; bum 60b mi;
expend 15b mi to speed up LIx opcodes, PUSH, POP, RSTR, and RSTRL
and to fix fault-handling bug in RDBL; restore AltoMode conditionals for
compatible Pilot and Alto sources.
Edit by Johnsson July 28, 1980 5:09 PM; trap fixup
Edit by Jim Frandeen July 7, 1980 10:18 AM: Check all 32 bits of base
registers instead of FixVA.
%

*Refill for page 4 opcodes
MesaRefill4:
PFetch4[PCB,IBuf,4], GoToP[MesaRefill], At[2377];

*The P4 double reads (LLDB and LGDB) are restartable regardless of which
*reference faults because the address of the fetch does not depend on
*the first stack word overwritten, so we can do these more straight-forwardly
*than the ones on P5.
P4FQT:
Skip[QuadOvf];
LU ← NextInst[IBuf], Call[P4Tailx];
Stack&-2, Return;*Point StkP at 1st word

P4IncT:
T ← (Zero) + T + 1, Return;


*Pilot Mesa should only get here if IntPending is set by an I/O controller.
*Alto Mesa also uses NOP for padding.
@NOP:
T ← (RZero) + 1, GoTo[NOPint,IntPending], Opcode[0];
P4Tail:
LU ← NextInst[IBuf];
P4Tailx:
NIRet;

%NOPint is entered from @NOP above, from BLTstop (in MesaX), from IdleLoop
(in MesaP), and from @ResetOnStack and @ReclaimAll in CedarGC. T holds the
amount by which to backup the PC. T may be 0 on call from IdleLoop.
MIPend(x) clears IntPending, starts an interrupt if interrupts are enabled
and requested, else returns. Return will cause a BLT to be restarted or send
control to the byte code that was elided when the NOP was forced.
%
:IF[AltoMode]; ****************************************
NOPint:
IntType ← T, LoadPage[prPage]; *IntType ← (PC backup if stopping)
T ← (SStkP&NStkP) xor (377C), CallP[MIPend]; *T ← StkP
LU ← NextInst[IBuf], Call[P4Tailx];

*unused opcodes on page 4
T ← sUnimplemented, GoTo[doTrapP4], Opcode[74];
T ← sUnimplemented, GoTo[doTrapP4], Opcode[75];
doTrapP4:
LoadPage[opPage3];
GoToP[kfcr];

*Add alpha to the long pointer at TOS and trap.
CBLsub:
LU ← Stack&-1, LoadPage[CBLPage];
Stack ← (Stack) + T;
OnPage[CBLPage];
Stack&+1, FreezeResult;
Stack ← (Stack) + 1, UseCOutAsCIn, Return;

T ← CNextData[IBuf], Call[CBLsub], Opcode[76];
T ← sWCBL, GoTo[doTrapP4];

T ← CNextData[IBuf], Call[CBLsub], Opcode[77];
T ← sICBL, GoTo[doTrapP4];

:ELSE; ************************************************
NOPint:
RTemp ← T, Call[MIPendy];*RTemp ← (PC backup if stopping)
*Must wait 1 mi for PCF← before NextInst.
GoTo[P4Tail];

*PC backup. Interrupts from BitBlt and TextBlt enter here only when the
*interrupt is certain to occur.
*IntPending is true implying NWW .ne. 0 here.
MIPend:
RTemp ← T;
*External call from MesaP IdleLoop enters here with RTemp = 0
MIPendy:
T ← (SStkP&NStkP) xor (377C);*Save StkP
WW ← IP[RSImage]C;
StkP ← WW, WW ← T, NoRegILockOK;
T ← Stack ← (Stack) and not (IntPendingBit);
LU ← xfWDC;
*T ← PC backup amount - 1
T ← (RTemp) - 1, RS232 ← T, GoTo[.+3,ALU=0];
*MesaP call cannot get here because it has previously checked for xfWDC#0,
*so the PC has to be backed up; however, this code should work even if the
*PC isn’t being backed up.
StkP ← WW;*Interrupts disabled
T ← (PCFreg) - T - 1, GoTo[BackPCa];
*Point at RSImage+1 .eq. NWW
Stack&+1, Skip[ALU<0];*Skip if no backup
T ← (PCFreg) - T - 1, Call[BackPCa];
T ← Stack, Task;*WW←NWW, NWW←0
Stack ← Zero;
StkP ← WW, WW ← T, NoRegILockOK, GoTo[Interrupt];

*External entries here from MesaJ and MesaP.
BackSPPCandTrap:
RTemp1 ← T;
StkP ← RTemp1, GoTo[BackPCandTrap];

*External entry from Alloc in MesaX.
*We always do PCF←PCX-1; PCB is backed up to the previous quadword when
*(PCX .ne. 0 & PCF .ne. PCX-1) % (PCF < PCX). We have to check for PCF .ne.
*PCX-1 because nested faults and traps may call BackPC several times.
BackPC:
LU ← (PCFreg) - T, Skip[ALU>=0];
T ← 7C, GoTo[.-1];
BackPCa:
RTemp1 ← T, Skip[ALU>=0];
PCB ← (PCB) - (4C);
PCF ← RTemp1, Return;

*(?) Load code overlay opcode for pilot loader presently identical to LIW
@LCO:
LU ← CycleControl ← NextData[IBuf], Call[LIWx], Opcode[74];

:IF[CedarMode]; ***************************************
*unused opcodes on page 4

RTemp ← 75C, GoTo[Parm0Trap], Opcode[75];
*If WithGarbCollect .eq. 1, code for AssignRef and AssignRefNew is in
*CedarGC.Mc
:UNLESS[WithGarbCollect]; *****************************
RTemp ← 76C, GoTo[Parm0Trap], Opcode[76];
RTemp ← 77C, GoTo[Parm0Trap], Opcode[77];
:ENDIF; ***********************************************

P4RTempToT:
T ← RTemp, Return;

Parm0Trap:
TrapParm ← 0C;
*Timing from here to SavePCXfer = 49 to 52 cycles.
*Have index into OpTrapTable in RTemp; SD[137] = pointer to OpTrapTable
UndefTrap:
RTemp1 ← Add[xfSDOffset!,137]C;
T ← (RTemp1) + (xfAV);
*Fetch SD[137]; T ← opcode or Misc alpha + 400b
PFetch1[MDS,RTemp1], Call[P4RTempToT];
T ← (RTemp1) + T;
*Fetch control link; P4RTempToT is called for tasking only.
BackTrap:
PFetch1[MDS,xfMX], Call[P4RTempToT];
LU ← xfMX, Call[BackTrap1];
LoadPage[xfPage1];
MemStat ← Or[Trap!,NoPushSD!]C, GoToP[SavePCXfer];

BackTrap1:
*Go if trap procedure is defined
T ← (PCXreg) - 1, GoTo[BackPC,ALU#0];
RTemp ← sUnimplemented;
BackPCandTrap:
RTemp ← (RTemp) + (xfAV);
T ← (RTemp) + (xfSDOffset), GoTo[BackTrap];

:ELSE; ************************************************

BackPCandTrap:
T ← (PCXreg) - 1, Call[BackPC];
T ← RTemp, LoadPage[opPage3];
MemStat ← Or[Trap!,NoPushSD!]C, GoToP[kfcr];

*unused opcodes on page 4
RTemp ← sUnimplemented, GoTo[BackPCandTrap], Opcode[75];
RTemp ← sUnimplemented, GoTo[BackPCandTrap], Opcode[76];
RTemp ← sUnimplemented, GoTo[BackPCandTrap], Opcode[77];

:ENDIF; **********************************************
:ENDIF; **********************************************

P4Push:
Stack&+1, FreezeResult, Return;

*Local opcodes
:IF[CacheLocals]; *************************************
@LL0:
T ← LocalCache0, GoTo[P4PushT], Opcode[10];
@LL1:
T ← LocalCache1, GoTo[P4PushT], Opcode[11];
@LL2:
T ← LocalCache2, GoTo[P4PushT], Opcode[12];
@LL3:
T ← LocalCache3, GoTo[P4PushT], Opcode[13];

@SL0:
T ← Stack&-1, GoTo[SL0x], Opcode[22];
@SL1:
T ← Stack&-1, GoTo[SL1x], Opcode[23];
@SL2:
T ← Stack&-1, GoTo[SL2x], Opcode[24];
@SL3:
T ← Stack&-1, GoTo[SL3x], Opcode[25];

StoreLocalCache:
LU ← NextInst[IBuf];
PStore4[LOCAL,LocalCache0,4], NIRet;

*Have to do Stack&-1 to interlock possible PFetch2 to the stack.
@PL0:
T ← Stack&-1, Call[P4Push], Opcode[33];
SL0x:
LocalCache0 ← T, GoTo[StoreLocalCache];
@PL1:
T ← Stack&-1, Call[P4Push], Opcode[34];
SL1x:
LocalCache1 ← T, GoTo[StoreLocalCache];
@PL2:
T ← Stack&-1, Call[P4Push], Opcode[35];
SL2x:
LocalCache2 ← T, GoTo[StoreLocalCache];
@PL3:
T ← Stack&-1, Call[P4Push], Opcode[36];
SL3x:
LocalCache3 ← T, GoTo[StoreLocalCache];

:ELSE; ************************************************
@LL0:
PFetch1[LOCAL,Stack,4], GoTo[P4Tail], Opcode[10];
@LL1:
PFetch1[LOCAL,Stack,5], GoTo[P4Tail], Opcode[11];
@LL2:
PFetch1[LOCAL,Stack,6], GoTo[P4Tail], Opcode[12];
@LL3:
PFetch1[LOCAL,Stack,7], GoTo[P4Tail], Opcode[13];

@SL0:
PStore1[LOCAL,Stack,4], GoTo[P4Tail], Opcode[22];
@SL1:
PStore1[LOCAL,Stack,5], GoTo[P4Tail], Opcode[23];
@SL2:
PStore1[LOCAL,Stack,6], GoTo[P4Tail], Opcode[24];
@SL3:
PStore1[LOCAL,Stack,7], GoTo[P4Tail], Opcode[25];

@PL0:
PStore1[LOCAL,Stack,4], GoTo[PutTail], Opcode[33];
@PL1:
PStore1[LOCAL,Stack,5], GoTo[PutTail], Opcode[34];
@PL2:
PStore1[LOCAL,Stack,6], GoTo[PutTail], Opcode[35];
@PL3:
PStore1[LOCAL,Stack,7], GoTo[PutTail], Opcode[36];

*PutTail:
Stack&+1, GoTo[P4Tail];*Invokes interlock, so ..
*Increment stkp by hand so not caught by interlock
PutTail:
T ← (SStkP&NStkP) xor (377C);
RTemp ← (Zero) + T + 1;
StkP ← RTemp, GoTo[P4Tail];
:ENDIF; ***********************************************

@LL4:
PFetch1[LOCAL,Stack,10], GoTo[P4Tail], Opcode[14];
@LL5:
PFetch1[LOCAL,Stack,11], GoTo[P4Tail], Opcode[15];
@LL6:
PFetch1[LOCAL,Stack,12], GoTo[P4Tail], Opcode[16];
@LL7:
PFetch1[LOCAL,Stack,13], GoTo[P4Tail], Opcode[17];

@LLB:
T ← NextData[IBuf], Call[LocalF], Opcode[20];

*In LLDB and LGDB, where are there are no complications with fault handling,
*the double fetch to the stack averages 2.75 cycles faster than 2 single
*fetches, assuming that .25 of the doublewords cross quadword boundaries.
@LLDB:
T ← NextData[IBuf], Opcode[21];
PFetch2[LOCAL,Stack], Call[P4FQT];
*If P4FQT returns, QuadOvf occurred and StkP has been restored to its value
*prior to the PFetch2.
PFetch1[LOCAL,Stack], Call[P4IncT];*Fetch & push 1st word
LocalF:
PFetch1[LOCAL,Stack], GoTo[P4Tail];*T+1 and push 2nd word

@SL4:
PStore1[LOCAL,Stack,10], GoTo[P4Tail], Opcode[26];
@SL5:
PStore1[LOCAL,Stack,11], GoTo[P4Tail], Opcode[27];
@SL6:
PStore1[LOCAL,Stack,12], GoTo[P4Tail], Opcode[30];
@SL7:
PStore1[LOCAL,Stack,13], GoTo[P4Tail], Opcode[31];

**Require alpha < 4 or alpha > 7 here if local cache is used.
@SLB:
T ← NextData[IBuf], Opcode[32];
PStore1[LOCAL,Stack], GoTo[P4Tail];


*Global opcodes

@LG0:
PFetch1[GLOBAL,Stack,3], GoTo[P4Tail], Opcode[37];
@LG1:
PFetch1[GLOBAL,Stack,4], GoTo[P4Tail], Opcode[40];
@LG2:
PFetch1[GLOBAL,Stack,5], GoTo[P4Tail], Opcode[41];
@LG3:
PFetch1[GLOBAL,Stack,6], GoTo[P4Tail], Opcode[42];
@LG4:
PFetch1[GLOBAL,Stack,7], GoTo[P4Tail], Opcode[43];
@LG5:
PFetch1[GLOBAL,Stack,10], GoTo[P4Tail], Opcode[44];
@LG6:
PFetch1[GLOBAL,Stack,11], GoTo[P4Tail], Opcode[45];
@LG7:
PFetch1[GLOBAL,Stack,12], GoTo[P4Tail], Opcode[46];

@LGB:
T ← NextData[IBuf], Call[GlobalF], Opcode[47];

@LGDB:
T ← NextData[IBuf], Opcode[50];
PFetch2[GLOBAL,Stack], Call[P4FQT];
*If P4FQT returns, QuadOvf occurred. See LLDB.
PFetch1[GLOBAL,Stack], Call[P4IncT];
GlobalF:
PFetch1[GLOBAL,Stack], GoTo[P4Tail];

@SG0:
PStore1[GLOBAL,Stack,3], GoTo[P4Tail], Opcode[51];
@SG1:
PStore1[GLOBAL,Stack,4], GoTo[P4Tail], Opcode[52];
@SG2:
PStore1[GLOBAL,Stack,5], GoTo[P4Tail], Opcode[53];
@SG3:
PStore1[GLOBAL,Stack,6], GoTo[P4Tail], Opcode[54];

@SGB:
T ← NextData[IBuf], Opcode[55];
PStore1[GLOBAL,Stack], GoTo[P4Tail];

*Load Immediate opcodes
@LI0:
LU ← NextInst[IBuf], Opcode[56];
Stack&+1 ← 0C, NIRet;
@LI1:
LU ← NextInst[IBuf], Opcode[57];
Stack&+1 ← 1C, NIRet;
@LI2:
LU ← NextInst[IBuf], Opcode[60];
Stack&+1 ← 2C, NIRet;
@LI3:
LU ← NextInst[IBuf], Opcode[61];
Stack&+1 ← 3C, NIRet;
@LI4:
LU ← NextInst[IBuf], Opcode[62];
Stack&+1 ← 4C, NIRet;
@LI5:
LU ← NextInst[IBuf], Opcode[63];
Stack&+1 ← 5C, NIRet;
@LI6:
LU ← NextInst[IBuf], Opcode[64];
Stack&+1 ← 6C, NIRet;

*LU ← NextInst[IBuf]; Stack&+1 ← (Stack&+1) or not (0C), NIRet;
*is faster here, but illegal to read stack, which might be empty, even though
*the stack data doesn’t affect the result.
@LIN1:
T ← (Zero) - 1, GoTo[P4PushT], Opcode[65];

@LINI:
LU ← NextInst[IBuf], Opcode[66];
Stack&+1 ← 100000C, NIRet;

@LIB:
T ← NextData[IBuf], Opcode[67];
*Also get here from MesaX
P4PushT:
LU ← NextInst[IBuf];
Stack&+1 ← T, NIRet;

:IF[AltoMode]; ****************************************
@LIW:
Cycle&PCXF, Skip[R Even], Opcode[70];
CSkipData;*Odd byte--can’t cause refill
T ← NextData[IBuf];
LU ← CycleControl ← CNextData[IBuf];*Can’t cause refill
T ← (LHMask[Cycle&PCXF]) or T, GoTo[P4PushT];
:ELSE; ************************************************
@LIW:
LU ← CycleControl ← NextData[IBuf], Opcode[70];
LIWx:
T ← LHMask[Cycle&PCXF];
:ENDIF; ***********************************************
LADRBx:
T ← (NextData[IBuf]) + T, Call[P4PushT];

@LINB:
T ← 177400C, GoTo[LADRBx], Opcode[71];

*Local Address Byte - since MDS is 64K aligned, the low half of the base register is L
@LADRB:
T ← LOCAL, GoTo[LADRBx], Opcode[72];

*Global Address Byte
@GADRB:
T ← GLOBAL, GoTo[LADRBx], Opcode[73];

*Common tail and refill for instructions on page 5
MesaRefill5: PFetch4[PCB,IBuf,4], GoToP[MesaRefill], At[2777];

P5Tail:
LU ← NextInst[IBuf];*Odd; paired with P5Trap
P5Tailx:
NIRet;

RWSTRx:
T ← (Stack&-1) + T;*string index
RTemp1 ← T;
T ← RSh[RTemp1,1];
AddTtoStack:
T ← (Stack&-1) + T, Return;

FetchMDSToRTemp:
PFetch1[MDS,RTemp];
RTemp1 ← T, Return;*Bypass kludge = no bypass kludge here

%StkP ← StkP+2, T ← T+1
This subroutine is used between the two PStore1’s which happen when a
PStore2 from the Stack crosses a quadword boundary; the Stack&+2 will abort
until the PStore1 finishes, so could save two cycles with:
IncS2T1:
RTemp ← (Zero) + T + 1;
T ← (SStkP&NStkP) - 1;
RTemp1 ← (Zero) - T;
StkP ← RTemp1;
T ← RTemp, Return;
Until we make space for this, use the following:
%
IncS2T1:
T ← (Zero) + T + 1;*Reversing these 2 mi saves 1 mi but
Stack&+2, Return;*costs 2 cycles.

P5IncT:
T ← (Zero) + T + 1, Return;

FetchLPToRTemp:
PFetch1[LP,RTemp];*allow time to write T
P5Ret:
Return;*allow time for T to be written

TtoRTemp:
RTemp ← T, Return;

P5FQT:
Skip[QuadOvf];
LU ← NextInst[IBuf], Call[P5Tailx];
*adjust StkP modified by the failed fetch to point one below the 2nd word
*to be fetched.
P5Pop:
Stack&-1, Return;

*Call here from RSTRL and WSTRL.
RWSTRLx:
T ← (Stack&-1) + T;
*Call here from RFSL and WFSL.
TtoR1StackLP:
RTemp1 ← T;*RTemp1 ← String index
*Call from MesaX
StackLP:
T ← Stack&-1;
StackLPx:
LPhi ← T, LoadPage[opPage0];
StackLPy:
*Call from MesaX
LU ← LdF[LPhi,0,12];*Test for out of bounds
OnPage[opPage0];
LPhi ← (LSh[LPhi,10]) + T + 1, Skip[ALU=0];
LPhi ← (Zero) - 1;*Cause map out of bounds
T ← Stack&-1;
LP ← T, Return;


*Read n, n=0-4
@R0:
T ← (Stack&-1) + (0C), GoTo[ReadTail], Opcode[100];
@R1:
T ← (Stack&-1) + (1C), GoTo[ReadTail], Opcode[101];
@R2:
T ← (Stack&-1) + (2C), GoTo[ReadTail], Opcode[102];
@R3:
T ← (Stack&-1) + (3C), GoTo[ReadTail], Opcode[103];
@R4:
T ← (Stack&-1) + (4C), GoTo[ReadTail], Opcode[104];

*Read Byte
@RB:
T ← CNextData[IBuf], Call[AddTtoStack], Opcode[105];
ReadTail:
PFetch1[MDS,Stack], GoTo[P5Tail];

*Write n, n=0-2
@W0:
T ← (Stack&-1) + (0C), GoTo[WriteTail], Opcode[106];
@W1:
T ← (Stack&-1) + (1C), GoTo[WriteTail], Opcode[107];
@W2:
T ← (Stack&-1) + (2C), GoTo[WriteTail], Opcode[110];

@WB:
T ← CNextData[IBuf], Call[AddTtoStack], Opcode[111];
:IF[CacheLocals]; *************************************
*PStore1’s can’t cause QuadOvf, so this checks the local cache
WriteTail:
PStore1[MDS,Stack], GoTo[SQT];
:ELSE; ************************************************
WriteTail:
PStore1[MDS,Stack], GoTo[P5Tail];
:ENDIF; ***********************************************

:IF[AltoMode]; ****************************************
*Read Field
@RF:
LU ← CycleControl ← NextData[IBuf], Opcode[112];
Cycle&PCXF, Skip[R Odd];*Align field
LU ← CycleControl ← NextData[IBuf];
T ← NextData[IBuf], Call[RFy];*Odd byte--no refill

@WF:
LU ← CycleControl ← NextData[IBuf], Opcode[113];
Cycle&PCXF, Skip[R Odd];*Align field
LU ← CycleControl ← NextData[IBuf];
T ← NextData[IBuf], Call[WFz];*Odd byte--no refill
:ELSE; ************************************************
@RF:
T ← NextData[IBuf], Opcode[112]; *get offset
LU ← CycleControl ← NextData[IBuf], Call[RFy]; *get field descriptor

@WF:
T ← NextData[IBuf], Opcode[113]; *get offset
LU ← CycleControl ← NextData[IBuf], Call[WFz]; *get field descriptor
:ENDIF; ***********************************************

*Read Double Byte
@RDB:
T ← CNextData[IBuf], Call[AddTtoStack], Opcode[114];
DoubleRead:
PFetch2[MDS,Stack], Call[P5FQT];
*If P5FQT Returns, QuadOvf occurred and StkP is 1 larger than it was before
*the PFetch2. Since the fetch address is a function of the 1st word
*overwritten, the two single fetches have to be accomplished in a way that
*does not allow the 1st stack word to be overwritten on a fault.
PFetch1[MDS,RTemp], Call[P5IncT];*Fetch 1st word
PFetch1[MDS,Stack];*Fetch 2nd word directly to stack
DoubleReadx:
Nop;
Nop;
T ← RTemp;*Move 1st word to stack
*Must allow the PFetch1[MDS,Stack] above time to fault before
*smashing the 1st stack word; a fault on that PFetch1 will abort
*this next mi.
***Stack&-1 will abort until PFetch1 finishes costing about 4 cycles.
Stack&-1 ← T, GoTo[PUSH];*& point StkP at 2nd word

*Read Double 0
@RD0:
T ← Stack&-1, GoTo[DoubleRead], Opcode[115];

*Write Double Byte
@WDB:
T ← CNextData[IBuf], Call[AddTtoStack], Opcode[116];
DoubleWrite:
PStore2[MDS,Stack], Call[SQT];
*If SQT Returns, StkP is one smaller than it was before the PStore2.
*Do two single stores
PStore1[MDS,Stack], Call[IncS2T1];
PStore1[MDS,Stack], GoTo[WSDBx];

*Write Double 0
@WD0:
T ← Stack&-1, GoTo[DoubleWrite], Opcode[117];

*Convert RTemp1 byte pointer to field pointer in CycleControl; put
*original T in RTemp1.
R1BtoF:
RTemp1 ← LSh[RTemp1,7];
RTemp1 ← (RTemp1) or (7C);
CycleControl ← RTemp1, RTemp1 ← T, NoRegILockOK, Return;

@RSTR:
T ← CNextData[IBuf], Call[RWSTRx], Opcode[120]; *get alpha
PFetch1[MDS,Stack], Call[R1BtoF];
*Jump here from RFC, RFS, and RFSL.
RFLx:
LU ← NextInst[IBuf];
RFLxx:
Stack ← RF[Stack], NIRet;

@WSTR:
T ← CNextData[IBuf], Call[RWSTRx], Opcode[121];
PFetch1[MDS,RTemp], Call[R1BtoF];
T ← WFA[Stack&-1], GoTo[WFy];

*Since MDShi = GLOBALhi = LOCALhi ...
GPPointer:
T ← (GLOBAL) + (3C), Skip;*offset of global 0
LPPointer:
T ← (LOCAL) + (4C);*offset of local 0
T ← (LdF[Cycle&PCXF,0,4]) + T;
PFetch1[MDS,RTemp], GoTo[LPPointerx];

*Read Indexed by Local Pair
@RXLP:
LU ← CycleControl ← CNextData[IBuf], Call[LPPointer], Opcode[122];
T ← (Stack&-1) + T, GoTo[RILPx];

*Write Indexed by Local Pair
@WXLP:
LU ← CycleControl ← CNextData[IBuf], Call[LPPointer], Opcode[123];
T ← (Stack&-1) + T, GoTo[WILPx];

*Read Indirect Local Pair
@RILP:
LU ← CycleControl ← CNextData[IBuf], Call[LPPointer], Opcode[124];
RILPx:
T ← (RTemp) + T, GoTo[ReadTail];

*Read Indirect Global Pair
@RIGP:
LU ← CycleControl ← CNextData[IBuf], Call[GPPointer], Opcode[125];
T ← (RTemp) + T, GoTo[ReadTail];

*Write Indirect Local Pair
@WILP:
LU ← CycleControl ← CNextData[IBuf], Call[LPPointer], Opcode[126];
WILPx:
T ← (RTemp) + T, GoTo[WriteTail];

*Read Indirect Local 0
:IF[CacheLocals]; *************************************
@RIL0:
T ← LocalCache0, GoTo[ReadTail], Opcode[127];
:ELSE; ************************************************
@RIL0:
PFetch1[LOCAL,RTemp,4], Call[P5Ret], Opcode[127];
T ← RTemp, GoTo[ReadTail];
:ENDIF; ***********************************************

*Write Swapped 0
@WS0:
T ← Stack&-1, Call[TtoRTemp], Opcode[130]; *T ← data
T ← Stack&-1, GoTo[WS0x];

*Write Swapped Byte
@WSB:
T ← Stack&-1, Call[TtoRTemp], Opcode[131];
T ← CNextData[IBuf], Call[AddTtoStack];
:IF[CacheLocals]; *************************************
WS0x:
PStore1[MDS,RTemp];

%Possible improvement here with the following code sequence, which almost
works except for bypass kludge. The exact condition for a LocalCache update
is that the store went to an address such that -4 >= LOCAL-addr >= 177771b.
Since T may contain either addr or addr+1 for a PStore2, approximate that
with 0 > LOCAL-T >= 177770b (i.e., test for Carry from the 10b+(LOCAL-T)).
Also fix code at WSDBx-1.
SQT:
T ← (LOCAL) - T, Skip[QuadOvf’];
P5Push:
Stack&+1, Return;
CLCR0:
LU ← (RSh[R400,5]) + T;
Skip[Carry’];
PFetch4[LOCAL,LocalCache0,4];
LU ← NextInst[IBuf], CallX[P5TailX];

Bypass kludge (or don’t care about bypass kludge after MDS reference)
Store quadword test (or QuadOvf impossible after PStore1)
%
SQT:
RTemp1 ← T, Skip[QuadOvf’];
P5Push:
Stack&+1, Return;*Point StkP to the 1st word to be stored
CLCR0:
T ← (RSh[LOCAL,2]) + 1; *Check for local cache refill
LU ← (RSh[RTemp1,2]) xor T;
Skip[ALU#0];
PFetch4[LOCAL,LocalCache0,4];
LU ← NextInst[IBuf], Call[P5Tailx];
:ELSE; ************************************************
WS0x:
PStore1[MDS,RTemp], GoTo[P5Tail];

SQT:
RTemp1 ← T, Skip[QuadOvf’];
P5Push:
Stack&+1, Return;*Point StkP to the 1st word to be stored
CLCR0:
LU ← NextInst[IBuf], Call[P5Tailx];
:ENDIF; ***********************************************

*Write Swapped Field
:IF[AltoMode]; ****************************************
@WSF:
Cycle&PCXF, Skip[R Even], Opcode[132];
CSkipData;*Odd byte--can’t cause refill
LU ← CycleControl ← NextData[IBuf];
T ← CNextData[IBuf], Call[P5Pop];
:ELSE; ************************************************
@WSF:
T ← NextData[IBuf], Opcode[132];
LU ← CycleControl ← CNextData[IBuf], Call[P5Pop];
:ENDIF; ***********************************************
T ← (Stack&+1) + T, Call[FetchMDSToRTemp];
T ← WFA[Stack&-2], GoTo[WFy];

*Write Swapped Double Byte
@WSDB:
T ← NextData[IBuf], Opcode[133];
Stack&-2;
T ← (Stack&+2) + T; *T ← pointer + alpha
PStore2[MDS,Stack];
RTemp1 ← T, Skip[QuadOvf];
:IF[CacheLocals]; *************************************
WSDBx:
Stack&-1, GoTo[CLCR0]; *back up StkP over pointer
:ELSE; ************************************************
WSDBx:
LU ← NextInst[IBuf], Call[POPx]; *back up StkP over pointer
:ENDIF; ***********************************************
*Do two single stores
Stack&+1;
PStore1[MDS,Stack], Call[IncS2T1];
PStore1[MDS,Stack];
Stack&-2, GoTo[CLCR0]; *back up StkP over lsb(data) and pointer

*Read Field Code
:IF[AltoMode]; ****************************************
@RFC:
LU ← CycleControl ← NextData[IBuf], Opcode[134];
Cycle&PCXF, Skip[R Odd];
LU ← CycleControl ← NextData[IBuf];
T ← CNextData[IBuf], Call[AddTtoStack];
:ELSE; ************************************************
@RFC:
T ← NextData[IBuf], Opcode[134]; *get offset
LU ← CycleControl ← CNextData[IBuf], Call[AddTtoStack]; *get field descriptor
:ENDIF; ***********************************************
PFetch1[CODE,Stack], GoTo[RFLx];

*Displacement is in left byte, FD is in right byte
:IF[AltoMode]; ****************************************
StackFD:
Cycle&PCXF, Skip[R Even];
RTemp ← T, CSkipData, Skip;*Odd byte--can’t cause refill
RTemp ← T;
:ELSE; ************************************************
StackFD:
RTemp ← T;
:ENDIF; ***********************************************
T ← RSh[RTemp,10], Return;*get displacement

*Read Field Stack
@RFS:
T ← CycleControl ← Stack&-1, Call[StackFD], Opcode[135];
RFy:
T ← (Stack&-1) + T; *add pointer
PFetch1[MDS,Stack], GoTo[RFLx];

*Write Field Stack
@WFS:
T ← CycleControl ← Stack&-1, Call[StackFD], Opcode[136];
*Also jump here from WF.
WFz:
T ← (Stack&-1) + T, Call[FetchMDSToRTemp]; *add pointer, fetch
T ← WFA[Stack&-1]; *field to be inserted
*Also jump here from WSF, WSTR
WFy:
RTemp ← (WFB[RTemp]) or T; *do insert
T ← RTemp1, GoTo[WS0x];

*Read Byte Long
@RBL:
T ← Stack&-1, Call[StackLPx], Opcode[137];
T ← NextData[IBuf], Call[RILPLx];*displacement from pointer

*Write Byte Long
@WBL:
T ← Stack&-1, Call[StackLPx], Opcode[140];
T ← NextData[IBuf], Call[WILPLx];*displacement

*Read Double Byte Long
@RDBL:
T ← Stack&-1, Call[StackLPx], Opcode[141];
T ← NextData[IBuf];
PFetch2[LP,Stack], Call[P5FQT];
*Unlike other double reads to the stack, the fetch address for RDBL depends
*on BOTH stack words overwritten, so the code must tolerate a fault on either
*PFetch1 below. The problem case is where the 2nd PFetch1 starts before the
*1st faults but the 2nd doesn’t fault because it is on a different page.
*To avoid this, ensure 3 mi between the two fetches.
PFetch1[LP,RTemp];
Call[P5IncT];
Nop;
PFetch1[LP,Stack], GoTo[DoubleReadx];

*Write Double Byte Long
@WDBL:
T ← Stack&-1, Call[StackLPx], Opcode[142];
T ← NextData[IBuf];
PStore2[LP,Stack], Call[SQT];
*Do two single stores
PStore1[LP,Stack], Call[IncS2T1]; *straigntforward increment of StkP aborts. We can speed this up by being more devious.
PStore1[LP,Stack], GoTo[WSDBx];

*Format a long pointer from a local selector,,offset pair
LocalLP:
T ← (LOCAL) + (5C);*MDShi=GLOBALhi=LOCALhi
decLPTR: *Note: high half of pointer is fetched first
T ← (LdF[Cycle&PCXF,0,4]) + T;
PFetch1[MDS,LPhi];
*Bypass kludge .eq. no bypass kludge because MDS .eq. 0
T ← (AllOnes) + T;
PFetch1[MDS,LP];
T ← LPhi;
LU ← LdF[LPhi,0,12];*Test for out of bounds
LPhi ← (LSh[LPhi,10]) + T + 1, Skip[ALU=0];
LPhi ← (Zero) - 1;*Cause map out of bounds
LPPointerx:
T ← LdF[Cycle&PCXF,4,4], Return;

*Format a long pointer from a global selector,,offset pair
GlobalLP:
T ← (GLOBAL) + (4C), GoTo[decLPTR];

*Read Indexed by Local Pair Long
@RXLPL:
LU ← CycleControl ← CNextData[IBuf], Call[LocalLP], Opcode[143];
T ← (Stack&-1) + T;
RXCheckOverflow:
Skip[Carry’];
LPhi ← (LPhi) + (400C) + 1, GoTo[.-1];*Even
RILPLx:
PFetch1[LP,Stack], GoTo[P5Tail];*Odd

*Write Indexed by Local Pair Long
@WXLPL:
LU ← CycleControl ← CNextData[IBuf], Call[LocalLP], Opcode[144];
T ← (Stack&-1) + T;
WXCheckOverflow:
Skip[Carry’];
LPhi ← (LPhi) + (400C) + 1, GoTo[.-1];
WILPLx:
PStore1[LP,Stack], GoTo[P5Tail];***Local cache chk?

*Read Indexed by Global Pair Long
@RXGPL:
LU ← CycleControl ← CNextData[IBuf], Call[GlobalLP], Opcode[145];
T ← (Stack&-1) + T, GoTo[RXCheckOverflow];

*Write Indexed by Global Pair Long
@WXGPL:
LU ← CycleControl ← CNextData[IBuf], Call[GlobalLP], Opcode[146];
T ← (Stack&-1) + T, GoTo[WXCheckOverflow];

*Read Indirect Local Pair Long
@RILPL:
LU ← CycleControl ← CNextData[IBuf], Call[LocalLP], Opcode[147];
PFetch1[LP,Stack], GoTo[P5Tail];

*Write Indirect Local Pair Long
@WILPL:
LU ← CycleControl ← CNextData[IBuf], Call[LocalLP], Opcode[150];
PStore1[LP,Stack], GoTo[P5Tail];***Local cache chk?

*Read Indirect Global Pair Long
@RIGPL:
LU ← CycleControl ← CNextData[IBuf], Call[GlobalLP], Opcode[151];
PFetch1[LP,Stack], GoTo[P5Tail];

*Write Indirect Global Pair Long
@WIGPL:
LU ← CycleControl ← CNextData[IBuf], Call[GlobalLP], Opcode[152];
PStore1[LP,Stack], GoTo[P5Tail];***Local cache chk?

*Read String Long
@RSTRL:
T ← CNextData[IBuf], Call[RWSTRLx], Opcode[153];
*The Nops below prevent occasional stack errors on some machines.
*No one knows exactly why.
*It’s related to the RDC Idle loop running during the tasking above
*and to fetching to the stack below.
Nop;
T ← RSh[RTemp1,1];
Nop;
PFetch1[LP,Stack], Call[R1BtoF];
LU ← NextInst[IBuf], Call[RFLxx];

*Write String Long
@WSTRL:
T ← CNextData[IBuf], Call[RWSTRLx], Opcode[154];
T ← RSh[RTemp1,1];
PFetch1[LP,RTemp], Call[R1BtoF];
T ← WFA[Stack&-1], GoTo[WFLz];

*Read Field Long
:IF[AltoMode]; ****************************************
@RFL:
LU ← CycleControl ← CNextData[IBuf], Call[StackLP], Opcode[155];
Cycle&PCXF, Skip[R Odd];
LU ← CycleControl ← NextData[IBuf];
T ← NextData[IBuf], Call[RFLy];
:ELSE; ************************************************
@RFL:
LU ← MNBR ← CNextData[IBuf], Call[StackLP], Opcode[155];
LU ← CycleControl ← NextData[IBuf];
T ← MNBR, GoTo[RFLy];
:ENDIF; ***********************************************

*Write Field Long
:IF[AltoMode]; ****************************************
@WFL:
LU ← CycleControl ← CNextData[IBuf], Call[StackLP], Opcode[156];
Cycle&PCXF, Skip[R Odd];
LU ← CycleControl ← NextData[IBuf];
T ← CNextData[IBuf], Call[FetchLPToRTemp];
:ELSE; ************************************************
@WFL:
LU ← MNBR ← CNextData[IBuf], Call[StackLP], Opcode[156];
LU ← CycleControl ← NextData[IBuf];
T ← MNBR, Call[FetchLPToRTemp];
:ENDIF; ***********************************************
RTemp1 ← T, GoTo[WFLy];

*Read Field Stack Long
@RFSL:
T ← CycleControl ← Stack&-1, Call[TtoR1StackLP], Opcode[157];
:IF[AltoMode]; ****************************************
Cycle&PCXF, Skip[R Even];
CSkipData;
:ENDIF; ***********************************************
T ← RSh[RTemp1,10];
*Jump here from RFL.
RFLy:
PFetch1[LP,Stack], GoTo[RFLx];

*Write Field Stack Long
@WFSL:
T ← CycleControl ← Stack&-1, Call[TtoR1StackLP], Opcode[160];
RTemp1 ← T ← RSh[RTemp1,10], Call[FetchLPToRTemp];
:IF[AltoMode]; ****************************************
Cycle&PCXF, Skip[R Even];
CSkipData;
:ENDIF; ***********************************************
*Jump here from WFL.
WFLy:
T ← WFA[Stack&-1];
*Jump here from WSTR.
WFLz:
RTemp ← (WFB[RTemp]) or T;
*Jump here from WFSL.
WFLx:
T ← RTemp1;
PStore1[LP,RTemp], GoTo[P5Tail];***Local cache chk?

*Lengthen Pointer
@LP:
T ← Stack&-1, Opcode[161];*pop to interlock PFetch2’s
Skip[ALU=0];*test for NIL
T ← RSh[MDShi,10];*push MDShi if non-NIL
*Jump here from DUP.
Dup1:
LU ← NextInst[IBuf];
Stack&+2 ← T, NIRet;

*Store Local Double Byte
@SLDB:
T ← NextData[IBuf], Opcode[162];
PStore2[LOCAL,Stack], Call[SQT];
PStore1[LOCAL,Stack], Call[IncS2T1];
PStore1[LOCAL,Stack], GoTo[WSDBx];

*Store Global Double Byte
@SGDB:
T ← NextData[IBuf], Opcode[163];
PStore2[GLOBAL,Stack], Call[SQT];
PStore1[GLOBAL,Stack], Call[IncS2T1];
PStore1[GLOBAL,Stack], GoTo[WSDBx];

PUSH:
LU ← NextInst[IBuf], CallX[.+2];
@PUSH:
LU ← NextInst[IBuf], Opcode[164];
Stack&+1, NIRet;

@POP:
LU ← NextInst[IBuf], Opcode[165];
*Jump here from WSDBx.
POPx:
Stack&-1, NIRet;

@EXCH:
T ← Stack&-1, Opcode[166];
*The preceding Stack&-1 has interlocked any PFetch to the stack.
*Want to do MNBR ← Stack, Stack ← T, NoRegILockOK; here instead of
*the next two mi, but that won’t interlock a PStore2 at Stack properly.
LU ← MNBR ← Stack&-1;
Stack&+1 ← T, LoadPage[opPage0];
T ← MNBR, GoToP[P4PushT];

:IF[AltoMode]; ****************************************
*Link Byte = PUSHX; LIB; SUB; SL0;, except that nothing is above StkP
@LINKB:
T ← NextData[IBuf], Opcode[167];
*Only done immediately after XFER, which leaves desired quantity in xfMX
xfMX ← T ← (xfMX) - T, LoadPage[opPage0];
LocalCache0 ← T, GoToP[StoreLocalCache];
:ELSEIF[CacheLocals]; **********************************
*Link Byte = PUSHX; LIB; SUB; SL0; xfMX is above StkP
@LINKB:
T ← CNextData[IBuf], Call[P5Push], Opcode[167];
Stack ← T ← (Stack) - T, LoadPage[opPage0];
Stack&-1, GoToP[SL0x];
:ELSE; ************************************************
@LINKB:
T ← CNextData[IBuf], Call[P5Push], Opcode[167];
Stack ← (Stack) - T;
PStore1[LOCAL,Stack,4], GoTo[P5Tail];
:ENDIF; ***********************************************

*LU ← NextInst[IBuf]; Stack&+1 ← Stack&+1, NIRet; won’t interlock odd PFetch2.
@DUP:
T ← Stack&-1, GoTo[Dup1], Opcode[170];

:IF[AltoMode]; ****************************************
P5Trap:
LoadPage[opPage3];
GoToP[kfcr];
:ELSE; ************************************************
P5Trap:
RTemp ← T, LoadPage[opPage0];
T ← SStkP, GoToP[BackSPPCandTrap];
:ENDIF; ***********************************************

@NILCK:
T ← Stack&-1, Opcode[171];
NILCKx:
A ← Stack&+1, T ← sPointerFault, NoRegILockOK, DblGoTo[P5Trap,P5Tail,ALU=0];

@NILCKL:
T ← Stack&-1, Opcode[172];
LU ← (Stack) or T, GoTo[NILCKx];

*Bounds Check - Trap if (TOS-1) >= TOS (unsigned)
@BNDCK:
Stack&-1, Opcode[173];
T ← Stack&+1;
LU ← (Stack&-1) - T - 1;
T ← sBoundsFault, DblGoTo[P5Trap,P5Tail,Carry’];

*Unimplemented opcodes on page 5
:IF[AltoMode]; ****************************************
T ← sUnimplemented, GoTo[P5Trap], Opcode[174];
T ← sUnimplemented, GoTo[P5Trap], Opcode[175];
T ← sUnimplemented, GoTo[P5Trap], Opcode[176];
T ← sUnimplemented, GoTo[P5Trap], Opcode[177];
:ELSEIF[CedarMode]; ***********************************
RTemp ← 174C, GoTo[UnimpP5], Opcode[174];
RTemp ← 175C, GoTo[UnimpP5], Opcode[175];
RTemp ← 176C, GoTo[UnimpP5], Opcode[176];
RTemp ← 177C, GoTo[UnimpP5], Opcode[177];

UnimpP5:
LoadPage[opPage0];
TrapParm ← 0C, GoToP[UndefTrap];
:ELSE; ************************************************
LoadPage[opPage0], GoTo[UnimpP5], Opcode[174];
LoadPage[opPage0], GoTo[UnimpP5], Opcode[175];
LoadPage[opPage0], GoTo[UnimpP5], Opcode[176];
LoadPage[opPage0], GoTo[UnimpP5], Opcode[177];

UnimpP5:
RTemp ← sUnimplemented, GoToP[BackPCandTrap];
:ENDIF; ***********************************************


:END[MesaLS];