:IF[AltoMode];	*Last edited 26 March 1981 by Ed Fiala
  TITLE[MesaLS.Alto.Mode];
:ELSEIF[CedarMode];
  TITLE[MesaLS.Cedar.Mode];
:ELSE;
  TITLE[MesaLS.Pilot.Mode];
:ENDIF;

*Common tail and refill for instructions on page 4

MesaRefill4:
	PFetch4[PCB,IBuf,4], GoToP[MesaRefill], At[2377];


MesaBBret:	*For Pilot BitBlt  **Should change BitBlt to use P4Tail
P4Tail:	LU ← NextInst[IBuf];	*Even placement
P4Tailx:	NIRet;

*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 ← (RMZero) + 1, DblGoTo[NOPint,P4Tail,IntPending], Opcode[0];

*NOPint is entered from @NOP above, from  BLTstop (in MesaX), and from
*IdleLoop in MesaP).  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, LoadPage[opPage3]; *RTemp ← (PC backup if stopping)
	T ← (SStkP&NStkP) xor (377C), CallP[MIPendx]; * T ← Stkp xor 377
	T ← (PCFreg) - T;
	RTemp ← T;
	PCF ← RTemp, Skip[ALU<0];
	  GoTo[P4Tail];	*wait one instruction for PCF← to take
	PCB ← (PCB) - (4C), GoTo[P4Tail];

BackSPPCandTrap:
	RTemp1 ← T;
	StkP ← RTemp1, GoTo[BackPCandTrap];

BackPC:	RTemp1 ← T, Skip[ALU>=0];
	  PCB ← (PCB) - (4C);
	LU ← (PCFreg) - T;
	PCF ← RTemp1, Skip[ALU>=0];
	  PCB ← (PCB) - (4C), Return;
P4Ret:	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];

*Add alpha to the long pointer at TOS and trap.
CBLTrap:
	T ← NextData[IBuf];
	LU ← Stack&-1;
	Stack ← (Stack) + T, UseCTask, Call[P4Push];
	Stack ← (Stack) + 1, UseCOutAsCIn, GoTo[Parm0Trap];

	RTemp ← 76C, GoTo[CBLTrap], Opcode[76];

	RTemp ← 77C, GoTo[CBLTrap], Opcode[77];

Parm0Trap:
	TrapParm ← 0C;
*Have index into OpTrapTable in RTemp
UndefTrap:
	RTemp1 ← Add[xfSDOffset!,137]C;
	T ← (RTemp1) + (xfAV);
	PFetch1[MDS,RTemp1], Task;	*SD[137] = pointer to OpTrapTable
	T ← RTemp;		*T ← opcode or Misc alpha + 400b
	T ← (RTemp1) + T;
BackTrap:	*P4IncT is a Nop here.
	PFetch1[MDS,xfMX], Call[P4IncT];	*Fetch control link
	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];
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

IncS2T1:	Stack&+2;	*StkP ← StkP+2, T ← T+1
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:
	T ← RTemp;		*Move 1st word to stack
	Stack&-1 ← T, GoTo[PUSH];	*and 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, 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];
*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];
	Nop;
*Must wait for fault before updating stack at DoubleReadx+1
	GoTo[DoubleReadx];	*Fault aborts this mi (?)

*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 ← 5C;
	T ← (LdF[Cycle&PCXF,0,4]) + T; *note - high half of pointer is fetched first
	PFetch1[LOCAL,LPhi];
decLPTR:	*Bypass kludge (ok because MDShi=GLOBALhi=LOCALhi)
	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 ← 4C;
	T ← (LdF[Cycle&PCXF,0,4]) + T; *note - high half of pointer is fetched first
	PFetch1[GLOBAL,LPhi], 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], 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 PStore 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; ***********************************************

@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:	Stack&+1, T ← sPointerFault, 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];