: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];