:TITLE[MesaOP0]; *Mesa opcodes 0b - 77b *25 August 1982 by Ed Fiala. PFetch4[PCB,IBuf,4], GoToP[MesaRefill], At[LShift[opPage0,10],377]; %When a device needs interrupt service, its service routine sets some bit in NWW and then sets IntPending true in the RS232 interface. IntPending causes NextInst to send control to @NOP below rather than to the next opcode's starting address. Since interrupt testing is handled automatically by the hardware, NOP is the only short-running opcode that needs to test for interrupts. Long or indefinitely executing opcodes also jump to NopInt when IntPending is true. BLTstop (MesaOP3) and @ResetOnStack and @ReclaimAll (CedarGC), @CKSUM (MesaESC), BitBlt, and TextBlt do this--BitBlt and TextBlt only call NopInt when xfWDC .eq. 0. NopInt backs up the PC, turns off IntPending in RSImage and in the RS232 hardware, and then restarts the opcode if xfWDC .ne. 0 or services the interrupt if xfWDC .eq. 0. IdleInt is called by the idle loop in MesaP. % @NOP: GoTo[NopInt,IntPending], Opcode[0]; P4Tail: LU _ NextInst[IBuf]; P4Tailx: NIRet; NopInt: T _ (PCXreg) - 1, Call[BackPC]; T _ (SStkP&NStkP) xor (377C); IdleInt: WW _ IP[RSImage]C, Task; StkP _ WW, WW _ T, NoRegILockOK; LU _ xfWDC; *Turn off IntPending in RSImage and in the hardware RS232. T _ Stack _ (Stack) and not (IntPendingBit), Skip[ALU=0]; StkP _ WW, RS232 _ T, GoTo[P4Tail]; Stack&+1, RS232 _ T; *Point at NWW *Do WW_NWW and then NWW_0. T _ Stack, Task; Stack _ 0C; StkP _ WW, WW _ T, NoRegILockOK, GoTo[Interrupt]; P4IncT: T _ (Zero) + T + 1, Return; %External entry from Alloc in MesaESC. We always do PCF_PCX-1; PCB is backed up to the previous quadword when (PCX .ne. 0 & PCF .ne. PCX-1) or (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: WW _ T, Skip[ALU>=0]; PCB _ (PCB) - (4C); PCF _ WW, Return; *UDIV, LUDIV, and NILCKL and BNDCK jump to P4Trap with SD offset in RTemp. *Cedar Esc opcodes jump here with EscTrapOffset - SDOffset + alpha in RTemp; *Cedar AssignRef opcode jumps here with EscTrapOffset - SDOffset + ARFakeAlpha *(=0) in RTemp. P4Trap: T _ SStkP; *Even; paired with P4NoTrap *PRTrap in MesaP jumps to BackSPPCandTrap. BackSPPCandTrap: WW _ T, Task; StkP _ WW; *Jumps here by undefined or unimplemented regular opcodes. SDTrap: T _ (RTemp) + (SDOffset); %Timing from here to SavePCXfer = 15 to 20 cycles. T has MDS displacement to control link at EscTrapOffset+alpha for Esc and EscL opcodes, and SDOffset+sOpcodeTrap for regular opcodes. TrapParm holds alpha for undefined or unimplemented Esc or EscL opcodes, the opcode number for regular opcodes. ***EXCEPT CedarGC FLEmptyTP and TSRunningTP are different trap parameters. % BackTrap: PFetch1[MDS,xfMX]; *Fetch control link T _ (PCXreg) - 1, Call[BackPC]; LoadPage[xfPage1]; MemStat _ Trap, GoToP[SavePCXfer]; :IF[CacheLocals]; ************************************* P4PushT: LU _ NextInst[IBuf]; Stack&+1 _ T, NIRet; *Timing: 8.25 cycles. @LL0: T _ LocalCache0, GoTo[P4PushT], Opcode[1]; *Load Local 0-3 @LL1: T _ LocalCache1, GoTo[P4PushT], Opcode[2]; @LL2: T _ LocalCache2, GoTo[P4PushT], Opcode[3]; @LL3: T _ LocalCache3, GoTo[P4PushT], Opcode[4]; P4PushTR: Stack&+1 _ T, Return; *Timing: 12.25 cycles. @LLD0: T _ LocalCache0, Call[P4PushTR], Opcode[16]; *Load Local Double 0-3 T _ LocalCache1, GoTo[P4PushT]; @LLD1: T _ LocalCache1, Call[P4PushTR], Opcode[17]; T _ LocalCache2, GoTo[P4PushT]; @LLD2: T _ LocalCache2, Call[P4PushTR], Opcode[20]; T _ LocalCache3, GoTo[P4PushT]; @LLD3: T _ LocalCache3, Call[P4PushTR], Opcode[21]; PFetch1[LOCAL,Stack,4], GoTo[P4Tail]; *Timing: 16.25 cycles. SL0: T _ Stack&-1, GoTo[SL0x], Opcode[31]; *Store Local 0-3 SL1: T _ Stack&-1, GoTo[SL1x], Opcode[32]; SL2: T _ Stack&-1, GoTo[SL2x], Opcode[33]; SL3: T _ Stack&-1, GoTo[SL3x], Opcode[34]; StoreLocalCache: LU _ NextInst[IBuf]; PStore4[LOCAL,LocalCache0,0], NIRet; P4Push: Stack&+1, FreezeResult, Return; *Store Local Double 0-3. Timing: 20.25 cycles SLD0-2, 27.25 cycles SLD3 *OK to jump to the opcode starting addresses because page faults are *impossible. @SLD0: T _ Stack&-1, Opcode[45]; LocalCache1 _ T, GoTo[SL0]; @SLD1: T _ Stack&-1, Opcode[46]; LocalCache2 _ T, GoTo[SL1]; @SLD2: T _ Stack&-1, Opcode[47]; LocalCache3 _ T, GoTo[SL2]; @SLD3: PStore1[LOCAL,Stack,4], GoTo[SL3], Opcode[50]; *Put Local 0-3, Byte. Timing 18.25 cycles. *Have to do Stack&-1 to interlock possible PFetch2 to the stack. @PL0: T _ Stack&-1, Call[P4Push], Opcode[55]; SL0x: LocalCache0 _ T, GoTo[StoreLocalCache]; @PL1: T _ Stack&-1, Call[P4Push], Opcode[56]; SL1x: LocalCache1 _ T, GoTo[StoreLocalCache]; @PL2: T _ Stack&-1, Call[P4Push], Opcode[57]; SL2x: LocalCache2 _ T, GoTo[StoreLocalCache]; @PL3: T _ Stack&-1, Call[P4Push], Opcode[60]; SL3x: LocalCache3 _ T, GoTo[StoreLocalCache]; *Timing: 20.25 cycles. @PLD0: T _ Stack&-1, Opcode[62]; LocalCache1 _ T; T _ Stack&+1, GoTo[Sl0x]; :ELSE; ************************************************ *Load Local 0-3. Timing: 11.25 cycles if next opcode(s) doesn't reference *TOS, else 16.25 cycles @LL0: PFetch1[LOCAL,Stack,0], GoTo[P4Tail], Opcode[1]; @LL1: PFetch1[LOCAL,Stack,1], GoTo[P4Tail], Opcode[2]; @LL2: PFetch1[LOCAL,Stack,2], GoTo[P4Tail], Opcode[3]; @LL3: PFetch1[LOCAL,Stack,3], GoTo[P4Tail], Opcode[4]; *Load Local Double 0-3 *Timing: 11.25 cycles if next opcode doesn't reference TOS, *else 16.25 cycles. @LLD0: PFetch2[LOCAL,Stack,0], GoTo[P4Tail], Opcode[16]; @LLD1: PFetch2[LOCAL,Stack,1], GoTo[P4Tail], Opcode[17]; @LLD2: PFetch2[LOCAL,Stack,2], GoTo[P4Tail], Opcode[20]; *Timing: 16.25 cycles if next opcode(s) doesn't reference TOS, else *22.25 cycles. @LLD3: PFetch1[LOCAL,Stack,3], Opcode[21]; PFetch1[LOCAL,Stack,4], GoTo[P4Tail]; *Store Local 0-3. Timing: 11.25 to 19.25 cycles. @SL0: PStore1[LOCAL,Stack,0], GoTo[P4Tail], Opcode[31]; @SL1: PStore1[LOCAL,Stack,1], GoTo[P4Tail], Opcode[32]; @SL2: PStore1[LOCAL,Stack,2], GoTo[P4Tail], Opcode[33]; @SL3: PStore1[LOCAL,Stack,3], GoTo[P4Tail], Opcode[34]; *Store Local Double 0-3. *Timing: 11.25 to 19.25 cycles. @SLD0: PStore2[LOCAL,Stack,0], GoTo[P4Tail], Opcode[45]; @SLD1: PStore2[LOCAL,Stack,1], GoTo[P4Tail], Opcode[46]; @SLD2: PStore2[LOCAL,Stack,2], GoTo[P4Tail], Opcode[47]; *Timing: 28.25 to 36.25 cycles. @SLD3: PStore1[LOCAL,Stack,4], Call[P4Ret], Opcode[50]; PStore1[LOCAL,Stack,3], GoTo[P4Tail]; *Put Local 0-3 @PL0: PStore1[LOCAL,Stack,0], GoTo[PutTail], Opcode[55]; @PL1: PStore1[LOCAL,Stack,1], GoTo[PutTail], Opcode[56]; @PL2: PStore1[LOCAL,Stack,2], GoTo[PutTail], Opcode[57]; @PL3: PStore1[LOCAL,Stack,3], GoTo[PutTail], Opcode[60]; *Put Local Double 0 @PLD0: PStore2[LOCAL,Stack,0], GoTo[Put2Tail], Opcode[62]; :ENDIF; *********************************************** *Load Local 4-14, Byte @LL4: PFetch1[LOCAL,Stack,4], GoTo[P4Tail], Opcode[5]; @LL5: PFetch1[LOCAL,Stack,5], GoTo[P4Tail], Opcode[6]; @LL6: PFetch1[LOCAL,Stack,6], GoTo[P4Tail], Opcode[7]; @LL7: PFetch1[LOCAL,Stack,7], GoTo[P4Tail], Opcode[10]; @LL8: PFetch1[LOCAL,Stack,10], GoTo[P4Tail], Opcode[11]; @LL9: PFetch1[LOCAL,Stack,11], GoTo[P4Tail], Opcode[12]; @LL10: PFetch1[LOCAL,Stack,12], GoTo[P4Tail], Opcode[13]; @LL11: PFetch1[LOCAL,Stack,13], GoTo[P4Tail], Opcode[14]; @LLB: T _ NextData[IBuf], CallX[LocalF], Opcode[15]; *Load Local Double 4-8, 10, Byte @LLD4: PFetch2[LOCAL,Stack,4], GoTo[P4Tail], Opcode[22]; @LLD5: PFetch2[LOCAL,Stack,5], GoTo[P4Tail], Opcode[23]; @LLD6: PFetch2[LOCAL,Stack,6], GoTo[P4Tail], Opcode[24]; @LLD7: PFetch1[LOCAL,Stack,7], Opcode[25]; PFetch1[LOCAL,Stack,10], GoTo[P4Tail]; @LLD8: PFetch2[LOCAL,Stack,10], GoTo[P4Tail], Opcode[26]; @LLD10: PFetch2[LOCAL,Stack,12], GoTo[P4Tail], Opcode[27]; *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 *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[30]; 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 *Store Local 4-10, Byte @SL4: PStore1[LOCAL,Stack,4], GoTo[P4Tail], Opcode[35]; @SL5: PStore1[LOCAL,Stack,5], GoTo[P4Tail], Opcode[36]; @SL6: PStore1[LOCAL,Stack,6], GoTo[P4Tail], Opcode[37]; @SL7: PStore1[LOCAL,Stack,7], GoTo[P4Tail], Opcode[40]; @SL8: PStore1[LOCAL,Stack,10], GoTo[P4Tail], Opcode[41]; @SL9: PStore1[LOCAL,Stack,11], GoTo[P4Tail], Opcode[42]; @SL10: PStore1[LOCAL,Stack,12], GoTo[P4Tail], Opcode[43]; **Require alpha > 4 here if local cache is used. @SLB: T _ NextData[IBuf], Opcode[44]; PStore1[LOCAL,Stack], GoTo[P4Tail]; *Store Local Double 4-6, 8, Byte @SLD4: PStore2[LOCAL,Stack,4], GoTo[P4Tail], Opcode[51]; @SLD5: PStore2[LOCAL,Stack,5], GoTo[P4Tail], Opcode[52]; @SLD6: PStore2[LOCAL,Stack,6], GoTo[P4Tail], Opcode[53]; @SLD8: PStore2[LOCAL,Stack,10], GoTo[P4Tail], Opcode[54]; *Stack&+n, GoTo[P4Tail]; *Invokes interlock, so .. *increment StkP by hand avoiding interlock. :IF[CacheLocals]; ************************************* *Jump here only from Put2Tail, where T contains LOCAL+0 to 4 if locals 0 to 3 *were touched. Put2Tail: T _ (LOCAL) - T; LU _ (Form4[AllOnes]) + T; T _ (SStkP&NStkP) - 1, FreezeResult; RTemp _ (Zero) - T, Skip[ALU<0]; PFetch4[LOCAL,LocalCache0,0]; PutTy: LU _ NextInst[IBuf]; StkP _ RTemp, NIRet; PutTail: T _ SStkP&NStkP; RTemp _ (Zero) - T, GoTo[PutTy]; :ELSE; ************************************************ Put2Tail: T _ (SStkP&NStkP) - 1, GoTo[PutTx]; PutTail: T _ SStkP&NStkP; PutTx: RTemp _ (Zero) - T; LU _ NextInst[IBuf]; StkP _ RTemp, NIRet; :ENDIF; *********************************************** **Require alpha > 4 here if local cache is used. @PLB: T _ NextData[IBuf], Opcode[61]; *Put Local Byte PStore1[LOCAL,Stack], GoTo[PutTail]; @PLDB: T _ MNBR _ NextData[IBuf], Opcode[63]; PStore2[LOCAL,Stack]; T _ (RZero) + T + 1, GoTo[Put2Tail,QuadOvf']; *Bypass kludge Stack&+2; PStore1[MDS,Stack], Task; T _ (AllOnes) + T; PStore1[MDS,Stack], GoTo[Put2Tail]; *Global opcodes @LG0: PFetch1[GLOBAL,Stack,0], GoTo[P4Tail], Opcode[64]; @LG1: PFetch1[GLOBAL,Stack,1], GoTo[P4Tail], Opcode[65]; @LG2: PFetch1[GLOBAL,Stack,2], GoTo[P4Tail], Opcode[66]; @LGB: T _ NextData[IBuf], CallX[GlobalF], Opcode[67]; @LGD0: PFetch2[GLOBAL,Stack,0], GoTo[P4Tail], Opcode[70]; @LGD2: PFetch2[GLOBAL,Stack,2], GoTo[P4Tail], Opcode[71]; @LGDB: T _ NextData[IBuf], Opcode[72]; PFetch2[GLOBAL,Stack], Call[P4FQT]; *If P4FQT returns, QuadOvf occurred. See LLDB. PFetch1[GLOBAL,Stack], Call[P4IncT]; GlobalF: PFetch1[GLOBAL,Stack], GoTo[P4Tail]; @SGB: T _ NextData[IBuf], Opcode[73]; PStore1[GLOBAL,Stack], GoTo[P4Tail]; *Bounds Check--Trap if 2OS >= TOS (unsigned) @BNDCK: Stack&-1, Opcode[74]; T _ Stack&+1; LU _ (Stack&-1) - T - 1; RTemp _ sBoundsTrap, GoTo[P4Trap,Carry']; P4NoTrap: LU _ NextInst[IBuf], CallX[P4Tailx]; *xfBrkByte contains 40400b + the break byte = (2001b+4*opcode) RCy 2. @BRK: LU _ (xfBrkByte) - (40400C), Opcode[75]; *Break T _ 40400C, Skip[ALU#0]; RTemp _ sBreakTrap, GoTo[SDTrap]; *Manually dispatch to the entry mi for the opcode. xfBrkByte _ LCy[xfBrkByte,2]; *P4IncT is used only for its "Return." APCTask&APC _ xfBrkByte, xfBrkByte _ T, NoRegILockOK, GoTo[P4IncT]; :UNLESS[WithCedar]; ************************************ P4Undef: RTemp _ sOpcodeTrap, GoTo[SDTrap]; @OP76: TrapParm _ 76C, GoTo[P4Undef], Opcode[76]; @OP77: TrapParm _ 77C, GoTo[P4Undef], Opcode[77]; :ENDIF; ************************************************(1792)\f5 11446f0 48f5 188f0 248f5 45f0 29f5 7f0 43f5 7f0 :END[MesaOP0];