: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]; (2048)\f5