:TITLE[MesaESC]; *ESC and ESCL opcodes %Ed Fiala 21 May 1984: Change VERSION date. Ed Fiala 17 April 1984: Debug @DSHIFT and @BLTLR; move refill trap to MesaOP2; fix bug in MapLP change; create lskPage; bum 1 mi in AllocFail; fix bug in @PO change; bum 1 mi at BLTSetup; bum 1 mi in @WRWP; fix bug at AllocFail reported by Blackman. Ed Fiala 10 November 1983: Change @ME and @MX from Esc to regular opcodes; restore @JS; move @NILCK, @UDIV, @LUDIV, @ROB; add @BNDCKL, @XE, @XF, @LSK; delete @LSTE, @LSTF, @SLOB, @LLOB, @DBS, WithNILCK, WithLInt, WithDLogic, LSPage; change traps; improve MapLP; deimplement LPChecking; change VERSION; change PO; change frame fault part of @AF. Ed Fiala 21 December 1982: Deimplement @JS opcode and put NILCK in its position (WithNILCK conditional). Ed Fiala 29 November 1982: Add LoadStack opcode = Esc 177b as a comment; needs more work to combine code with LSTE and LSTF. Ed Fiala 3 November 1982: Add UserTimer opcode = Esc 214b; so far, only used by PathFinder configuration; adds 2b mi on moPage. Ed Fiala 13 October 1982: Fix bug in LSTE causing source link from LoadState table to be smashed with a link for the enclosing frame. Ed Fiala 23 August 1982: Fix @AF to reflect change to xfer allocate subroutine. Ed Fiala 27 May 1982: Fix @WRWP to set or clear IntPendingBit. Ed Fiala 24 May 1982: Move @LONGBLKZ and @LOCALBLKZ to Cedar1.Mc; replace NoPushSD by PushSD in Xfer MemStat of @LSTE and @LSTF; make csPage; fix CacheLocals=1 bug in @DSK; change in @PI:. Ed Fiala 13 May 1982: Change @VERSION to days since 1 Jan 1901; improve tasking in @PI. ***Placement is as follows: 271b mi on moPage 113b mi on xfPage1 23b mi on opPage0 5b mi on opPage1 (+1b mi if CacheLocals=1) 2b mi on opPage2 40b mi on opPage3 3b mi on wrMDSPage 27b mi on csPage 20b mi on lskPage 1b mi on piPage 1b mi on dvPage1 2b mi on ppPage +4b mi on moPage if WithBLEL=1 +25b mi on opPage3 if WithBLEL=1 +5b mi on opPage0 if WithBLEL=1 +5b mi on moPage if WithTMS1000=1 +3b mi on opPage1 if WithTMS1000=1 -1b mi on moPage if WithFloatingPoint=1 -1b mi on moPage if WithCedar=1 +1b mi on moPage if WithBitBlt=1 +1b mi on moPage if WithTextBlt=1 +13b mi on opPage3 if WithBLTLR=1 +2b mi on moPage if WithBLTLR=1 +2b mi on moPage if WithRotate=1 +1b mi on opPage1 if WithRotate=1 +44b mi on dsPage0 if WithDShift=1 (must be page with refill) +1b mi on moPage if WithDShift=1 POSSIBLE CHANGES: 1) Minimal stack error checks for (?) BitBlt, CKSUM, ? 2) Error checks for real page number and virtual page number in @SM, etc. 3) Implement @BYTBLT, @BYTBLTR? 4) Check @BLTLR, @ROTATE. 5) PStore1[MDS,RTemp] could be subr shared with MesaOP3. 6) Assign distinct trap location for AssignRef opcode. 7) Is LocalCache reload needed at @WOB exit? 8) Bum the common entry sequences for BLTLR, BLEL, and BLECL. % OnPage[moPage]; *At BackTrap, the address of the control link will be computed as *RTemp+T = EscTrapOffset+(2xalpha). moUnimp: xfTrapParm0 _ T, LoadPage[opPage0]; *Even placement moUnimpx: T _ (RTemp) + (EscTrapOffset), GoToP[BackTrap]; moStkPSave: T _ (SStkP&NStkP) xor (377C); moStkPSwap: RTemp _ T, StkP _ RTemp, NoRegILockOK, Return; moPsh: LU _ NextInst[IBuf]; Stack&+1, NIRet; moPshRRTemp: T _ (SStkP&NStkP) xor (377C), Call[moStkPSwap]; T _ Stack, Call[moStkPSwap]; *T _ RM register, restore StkP moPushT: LU _ NextInst[IBuf]; Stack&+1 _ T, NIRet; moRet: Return; %ESC and ESCL are distinct opcodes because the Dorado IFU must determine opcode length without reference to alpha. However, this implementation uses the same dispatch table for both opcodes to save microcode space. ESC and ESCL are defined to trap at MDS[EscTrapOffset+alpha] with parameter alpha when undefined. CedarGC opcodes presently trap with parameter 1 in the no-more-free-list-cells case or 2 in the trace-and-sweep-running case. Alpha dispatch is to moPage where possible because this results in 2 or 4 cycles faster execution than when the Dispatch at EscDFirst is abandoned to change pages. Timing for the alpha dispatch when the first mi is on moPage is 4.5 (buffer refill) + 10 = 14.5 cycles for alpha < 200b, and 4.5 + 14 = 18.5 cycles for alpha >= 200b. % MC[EscLast,216]; *ESC--extended Opcodes accessed by dispatching on alpha. @ESC: T _ MNBR _ CNextData[IBuf], Call[EscDispatch], Opcode[370]; LU _ NextInst[IBuf], CallX[P7Tailx]; *ESCL--extended opcodes dispatching on alpha using beta as operand. @ESCL: T _ MNBR _ CNextData[IBuf], Call[EscDispatch], Opcode[371]; LU _ NextInst[IBuf], CallX[P7Tailx]; EscDispatch: RTemp _ T, LoadPage[moPage], Skip[H2Bit8]; Dispatch[RTemp,10,4], GoToP[EscDFirst]; LU _ (RTemp) - (EscLast) - 1, GoToP[.+1]; OnPage[moPage]; Dispatch[RTemp,10,4], GoTo[moUnimp,ALU>=0]; EscDFirst: Dispatch[RTemp,14,4], Disp[.+1]; *Dispatch on 2nd byte xfTrapParm0 _ T, LoadPage[xfPage1], Disp[Esc00], At[EscTop,0]; * 0b-17b Disp[Esc20], At[EscTop,1]; *20b-37b Disp[Esc40], At[EscTop,2]; *40b-57b xfTrapParm0 _ T, LoadPage[opPage0], GoTo[moUnimpx], At[EscTop,3]; :UNLESS[WithFloatingPoint]; **************************** MesaFP xfTrapParm0 _ T, LoadPage[opPage0], GoTo[moUnimpx], At[EscTop,4]; :ENDIF; ************************************************ xfTrapParm0 _ T, LoadPage[opPage0], GoTo[moUnimpx], At[EscTop,5]; :UNLESS[WithCedar]; ************************************ CedarGC xfTrapParm0 _ T, LoadPage[opPage0], GoTo[moUnimpx], At[EscTop,6]; :ENDIF; ************************************************ Disp[Esc160], At[EscTop,7]; *160b-177b Disp[Esc200], At[EscTop,10]; *200b-217b OnPage[xfPage1]; xfUnimp: T _ (RTemp) + (EscTrapOffset), GoToP[BackTrap]; @a00: LoadPage[opPage0], GoToP[xfUnimp], At[EscD0,0]; @a01: LoadPage[opPage0], GoToP[xfUnimp], At[EscD0,1]; *2 to 6 (@MW, @MR, @NC, @BC, and @REQ) are in MesaP.Mc. %Map opcodes XMap[LP,xBuf,0] writes the map from xBuf and dumps the old contents into xBuf1, xBuf2, and xBuf3. Timing is as follows: 2 cycles for the XMap mi, 7 cycles in MC1, 1 cycle of RM transport, 2 more cycles in MC1, and 3 final cycles of RM transport. These opcodes deal with 32-bit virtual and real page numbers for machine independence, but only 12d bits of real page number and 14d bits of virtual page number are legal here. Higher bits of real page number and bits of virtual page number above 16d are thrown away without any error checks. Since pages are 256d words long, LP/LPhi are loaded from the virtual page number lshift 8. Since displacement from LP/LPhi is 0, only the left-half of LPhi need be valid. Since a map entry may be in use by an io task while being changed, no tasking may occur when the map is invalid. Set Map (Timing: 42.5 cycles) accepts: TOS/ Flags (12d=LogSE, 13d=protected, 14d=dirty, 15d=referenced) 2OS,,3OS/ Real page number (***high part and top 4 bits of low part are assumed 0) 4OS,,5OS/ Virtual page number (***high part assumed 0) Writes the map and returns with stack popped five times. % Esc00: @SM: T _ LSh[Stack&-2,14], GoToP[.+1], At[EscD0,7]; OnPage[xfPage1]; *Get RPlo and pop StkP across VPhi. T _ (LdF[Stack&-2,4,14]) or T, Task; xBuf _ T; ***Clear LogSE because of LoadPage problems when single-errors are logged. xBuf _ (xBuf) and not (100000C), Call[MapLP]; SM1: XMap[LP,xBuf,0], Call[xfRet]; *Need this extra task here xfTail: LU _ NextInst[IBuf]; xfTailx: MemStat _ Normal, NIRet; *Subr MapLP creates a BR pair from a virtual page for the Map opcodes. MapLP: T _ Stack; MapLPx: LPhi _ T; *Only the left-half of LPhi matters for disp=0. T _ LSh[Stack&-1,10], Skip[R>=0]; LPhi _ (LPhi) or not (0C); *VA>=2^22 = VP>= 2^16 illegal LP _ T, Return; *Subroutine MapPushOld pushes old flags; returns value for restoring map in T. MapPushOld: T _ LSh[xBuf3,10]; *Put flags,,card,blk0 in left byte *T _ value for restoring map entry (complement all the bits to high true) T _ xBuf1 _ (RHMask[xBuf1]) xnor T; *blk1,rowaddr in low byte *NOTE: must be non-tasking return because map invalid here. Stack&+1 _ T, UseCTask; Stack _ RSh[Stack,14], Return; *Old flags right-justified %Set Map Flags (Timing ~ 77.5 to 85.5 cycles) accepts: TOS/ New map flags 2OS,,3OS/ Virtual page number Unless entry is empty, writes the map with the new flags and returns: TOS,,2OS/ Real page number 3OS/ Old map flags % @SMF: T _ LSh[Stack&-2,14], GoToP[.+1], At[EscD0,10]; OnPage[xfPage1]; xBuf _ T, Call[MapLP]; **Non-tasking time is about 51 cycles here. XMap[LP,xBuf,0], Call[MapPushOld]; LU _ (LdF[xBuf3,11,3]) - 1; *=0 if map entry = VACANT *Rewrite the map entry with the old flags and page if it was vacant *(defined as protected, dirty, and referenced); otherwise, rewrite with new *flags and old page. Stack&+1 _ T, GoTo[SM0,ALU=0]; T _ Stack _ (Stack) and not (170000C); *Low part of old real page **LogSE ignored here because of LoadPage gotcha problems. xBuf _ (LdF[xBuf,1,17]) or T, GoTo[SM2]; *New flags, old page %Get Map Flags (Timing: 69.5 to 76.5 cycles) accepts: TOS,,2OS/ Virtual page number Reads the map and returns: TOS,,2OS/ Real page number 3OS/ Map flags % @GMF: LU _ Stack&-1, GoToP[.+1], At[EscD0,11]; OnPage[xfPage1]; T _ Stack, Call[MapLPx]; **Non-tasking time is about 48 cycles here. XMap[LP,xBuf,0], Call[MapPushOld]; Stack&+1 _ T; SM0: Stack _ (Stack) and not (170000C); *Low part of real page xBuf _ T; *Restore old flags and page SM2: Stack&+1 _ 0C, GoTo[SM1]; *Allocate Frame (Timing: 40.5 + WriteTail + 23 cycles/indirect) @AF: T _ (Stack&-1) + (AVOffset), GoToP[.+1], At[EscD0,12]; *T _ FSI+xfAV OnPage[xfPage1]; PFetch1[MDS,xfTemp]; *Head-of-list (can't fault) prData _ T, Call[TtoxfCount]; *Indirect allocate returns here LU _ LdF[xfTemp,16,1], GoTo[AllocFail,R Odd]; T _ xfTemp, Skip[ALU=0]; xfTemp _ RSh[xfTemp,2], GoTo[AllocInd]; *In MesaOP3 *Allocate succeeded; complete allocate and done. PFetch1[MDS,RTemp]; *This is last reference that can fault. Stack&+1 _ T, Task; T _ xfCount; PStore1[MDS,RTemp], GoTo[xfTail]; *Allocate failed. Backup PC and StkP and cause FrameFault with original *FSI as trap parameter in prData and qFrameFaultOs in prConditionQ. AllocFail: prData _ (prData) - (AVOffset); Stack&+1, LoadPage[opPage0]; prConditionQ _ qFrameFaultOs, GoToP[prBackPCFault]; *FreeFrame (Timing: 60.5 to 67.5 cycles) @FF: T _ (Stack&-1) - (4C), GoToP[.+1], At[EscD0,13]; OnPage[xfPage1]; PFetch1[MDS,xfFSI], Task; xfFrame _ T; xfFSI _ RHMask[xfFSI], Call[FreeSub0]; PStore1[MDS,xfFrame], GoTo[xfTail]; %Port In [S+2] = source link of previous xfer (usually LOCAL of previous context) [S+1] = indirect destination link of previous xfer (pointer to port) Zero port.inport (only the first word of the input port has to be zeroed). If the source link is non-zero, then store it in port.outport. Timing: 50.5 to 57.5 cycles if CacheLocals=0 and both PStore1's are done. % @PI: Stack&+2, GoToP[.+1], At[EscD0,14]; OnPage[xfPage1]; T _ Stack&-1, LoadPage[piPage]; RTemp _ T, LoadPage[opPage1]; *RTemp _ source link OnPage[piPage]; :IF[CacheLocals]; ******************************** T _ Stack, GoToP[portinz,ALU=0]; OnPage[opPage1]; PStore1[MDS,RZero], Call[P5Ret]; T _ (Form2[AllOnes]) + T; portinz: PStore1[MDS,RTemp]; *Since LOCAL is quadword-aligned, a port in LOCAL 0 to 3 can only begin *at LOCAL+2; if so, reload store-through LOCAL cache. T _ LOCAL; LU _ (Form-4[Stack&-1]) - T, GoTo[CLCR2]; :ELSE; ******************************************* T _ Stack&-1, SkipP[ALU#0]; *T _ [S+1] OnPage[opPage1]; PStore1[MDS,RTemp], Return; *Source = 0 => port.inport_0 & exit PStore1[MDS,RZero], Task; *Port.inport _ 0. T _ (Form2[AllOnes]) + T; *Port.outport _ source link. PStore1[MDS,RTemp], GoTo[P5Tail]; :ENDIF; ****************************************** %Port Out. The port is a four-word structure which begins with a word that is 2 mod 4 aligned (so that a pointer to the port is an indirect control link). [S],[S-1] is a long pointer to the port, but since the port is known to be in MDS, the high part of the long pointer is ignored. inport _ LOCAL (word 0 only; word 1 doesn't matter since LOCAL is type 0) xfTemp/xfTemp1 _ destination link from words 2 and 3 of the port. xfMY _ short pointer to the port (= indirect link). Timing = (14.5-2.25)+44-8 = 48.25 cycles to Xfer. % @PO: Stack&-1, GoToP[.+1], At[EscD0,15]; OnPage[xfPage1]; POR1: T _ (Stack&-1) + (2C); *Destination link into xfTemp/xfTemp1 from the outport. PFetch2[MDS,xfTemp], Task; xfMY _ T; xfMY _ T _ (xfMY) - (2C); *Save LOCAL in word 0 of inport PStore1[MDS,LOCAL], Call[SavPCinFrame]; PStore1[MDS,xfOldPC]; MemStat _ Or[EarlyXfer!,xfTypePORT!]C, GoTo[Xfer]; *Port Out Responding @POR: Stack&-1, GoToP[POR1], At[EscD0,16]; *Esc 17b (@SPP) is in MesaP.Mc Esc20: *Disable Interrupts (Timing: 23.5 cycles). @DI: xfWDC _ (xfWDC) + 1, At[EscD1,0]; Skip[ALU=0]; Iok: LU _ NextInst[IBuf], CallX[moTailx]; IErr: LoadPage[opPage0]; RTemp _ sInterruptError, GoToP[P4Trap]; *Enable Interrupts--also jump here from @WRWDC. *Timing: 14.5+17 cycles if NWW .eq. 0 else 14.5+20 cycles. EI: RTemp _ IP[NWW]C, At[EscD1,1]; T _ (SStkP&NStkP) xor (377C), Call[moStkPSwap]; LU _ Stack&-1; *Test NWW, point StkP at RSImage xfWDC _ (xfWDC) - 1, Skip[ALU#0]; *Carry' implies that the old value was 0 and is going negative. StkP _ RTemp, DblGoTo[IErr,Iok,Carry']; *Set IntPending in RS232 and in RSImage T _ Stack _ (Stack) or (IntPendingBit), Skip[Carry]; StkP _ RTemp, RS232 _ T, GoTo[IErr]; StkP _ RTemp, RS232 _ T, GoTo[moTail]; *Exclusive Or (Timing: 20.5 cycles). @XOR: T _ Stack&-1, At[EscD1,2]; LU _ NextInst[IBuf]; Stack _ (Stack) xor T, NIRet; OnPage[ppPage]; PshPop2: Stack&+1; T _ Stack&-2, Return; *Double And (Timing: 28.5 cycles). @DAND: T _ Stack&-2, LoadPage[ppPage], At[EscD1,3]; Stack _ (Stack) and T, CallP[PshPop2]; Stack _ (Stack) and T, GoTo[moPsh]; *Double Inclusive Or (Timing: 28.5 cycles). @DIOR: T _ Stack&-2, LoadPage[ppPage], At[EscD1,4]; Stack _ (Stack) or T, CallP[PshPop2]; Stack _ (Stack) or T, GoTo[moPsh]; *Double Exclusive Or (Timing: 28.5 cycles). @DXOR: T _ Stack&-2, LoadPage[ppPage], At[EscD1,5]; Stack _ (Stack) xor T, CallP[PshPop2]; Stack _ (Stack) xor T, GoTo[moPsh]; %CycleControl controls the action of the RF, WFA, and WFB functions; bits 0:3 of CycleControl are D, bits 4:7 are M. RF right-justifies a register and masks out all but M bits of a field: A _ RCy[Reg,15d-D-M] & Mask1[M] where Mask1[M] contains 1's in bits 15d-M through 15d. WFA shifts a source register to its correct position in the destination and masks out all bits except those in the field: A _ LCy[Reg,15-D-M] & Mask2[D,M] -or- A _ RCy[Reg,D+M+1] & Mask2[D,M] where Mask2[D,M] contains 1's in bits D through D+M. WFB inserts a field in the destination word: A _ (Reg) and not Mask2[D,M]. Rotate--have trap support (Timing: 26.5 cycles). Left cycles 2OS by TOS bits?? To do this CycleControl must be loaded with the left-cycle count in the 1st nibble and 17b in the 2nd nibble; then RF is used to cycle the stack. % :IF[WithRotate]; *************************************** @ROTATE: T _ LSh[Stack&-1,4], At[EscD1,6]; RTemp _ T, LoadPage[opPage1]; RTemp _ (RTemp) or (17C); OnPage[opPage1]; CycleControl _ RTemp, GoTo[RFLx]; *RFLx in MesaOP1.Mc. :ELSE; ************************************************* @ROTATE: xfTrapParm0 _ T, LoadPage[opPage0], GoTo[moUnimpx], At[EscD1,6]; :ENDIF; ************************************************ %Double Shift--have trap support TOS = shift count (+ .eq. left, - .eq. right), 2OS,,3OS = doubleword shifted. Timing: 28.5 cycles if S .ge. 40b; 30.5 cycles if S .le. -40b; 32.5 cycles if S .eq. -20b; 45.5 or 48.5 cycles if 0 .le. S .le 37b 42.5 or 45.5 cycles if -1 .ge. S .ge. -37b and S .ne. -20b. % :IF[WithDShift]; *************************************** @DSHIFT: T _ Stack&-1, LoadPage[dsPage0], At[EscD1,7]; *For a left shift by S, load CycleControl with D,,M = 0,,17b-S and use WFA. *For a right shift by 20b-S, load CycleControl with D,,M = 0,,S-1 and use RF. RTemp _ T, GoToP[DShiftRight,ALU<0]; *Shifting left. OnPage[dsPage0]; LU _ (RTemp) - (40C); *Point StkP at low-order word. Stack&-1, Skip[ALU<0]; T _ Stack _ 0C, GoTo[DS0Push0]; *LShift .ge. 40b gives zero T _ (RTemp) or (360C); LU _ LdF[RTemp,13,1]; *For leftshift by S, the control 0,,17b-S is generated as 377b - (17b,,S). T _ (R400) - T - 1, GoTo[DSL1,ALU=0]; *377 - T. *Left-shift of 20b .le. S .le. 37b. RTemp _ T, Call[RTempToCycle]; T _ WFA[Stack]; Stack _ 0C; LU _ NextInst[IBuf]; Stack&+1 _ T, NIRet; RTempToCycle: CycleControl _ RTemp, Return; *Left-shift of 0 .le. S .le. 17b: right-shift high-order word first. *For rightshift by 20b-S (0=0]; T _ Stack&-1 _ 0C, GoTo[DS0Push0]; *Shift .le. -40b gives 0 *For leftshift (WFA) by 20b-(-S), control is DBX=0, MWX=-(S mod 20b)-1 *= (S mod 20b)' = [(S mod 20b) xor 17b] for (-S mod 20b) .ne. 0. T _ (LdF[AllOnes,14,4]) xor T, Skip[ALU#0]; Stack&-1 _ Stack&-1, GoTo[DS0Push0]; *Shift of exactly -20b RTemp1 _ T; *(S mod 20b)' *For rightshift (RF) by -S mod 20b, control is DBX=0, MWX=(S-1) mod 20b *which is equivalent to DBX=0, MWX=(S mod 20b)-1 because S=0 has been *eliminated. T _ (LdF[RTemp,14,4]) - 1; CycleControl _ RTemp1, RTemp1 _ T, NoRegILockOK; T _ WFA[Stack]; LU _ LdF[RTemp,13,1]; CycleControl _ RTemp1, Skip[ALU#0]; *21b .le. S .le. 37b: copy shifted high word to low and zero high word. Stack&-1 _ RF[Stack&-1], GoTo[DS0Push0]; Stack _ RF[Stack]; *Right shift high word Stack&-1, LoadPage[moPage]; *Right shift low word, ORing bits shifted left from high word Stack _ (RF[Stack]) or T, GoToP[moPsh]; DS0Push0: LU _ NextInst[IBuf]; Stack&+1 _ 0C, NIRet; :ELSE; ************************************************* @DSHIFT: xfTrapParm0 _ T, LoadPage[opPage0], GoTo[moUnimpx], At[EscD1,7]; :ENDIF; ************************************************ *Lengthen Integer (Timing: 23.5 or 24.5 cycles). @LINT: T _ Stack&-1, LoadPage[opPage2], Skip[R<0], At[EscD1,10]; T _ 0C, GoToP[SkipPushT]; T _ AllOnes, GoToP[SkipPushT]; *SkipPushT in MesaOP2.Mc *Jump Stack (Timing: 38.5 cycles). @JS: LU _ PCF _ Stack&-1, At[EscD1,11]; Stack&+1, LoadPage[opPage2]; T _ RSh[Stack&-1,1]; OnPage[opPage2]; *PFetch4 on same page as jumps for Fault.Mc PFetch4[CODE,IBuf]; PCB _ T, GoTo[P6Tail]; *Bypass kludge *Read Code Field Stack (Timing: 38.5 cycles). @RCFS: T _ RSh[Stack&-1,10], At[EscD1,12]; *T _ Desc.Offset T _ (Stack&+1) + T, LoadPage[opPage1]; *Offset + Desc.Offset CycleControl _ Stack&-2; *Desc.Field OnPage[opPage1]; PFetch1[CODE,Stack], GoTo[RFLx]; *Read Code (Timing: 29.75 cycles to 34.75 cycles). @RC: T _ NextData[IBuf], At[EscD1,13]; T _ (Stack&-1) + T; PFetch1[CODE,Stack], GoTo[moTail]; *Divide--(0,,2OS)/TOS. Single word dividend and divisor, no overflow check. *The remainder is left above the Stack. @UDIV: LU _ MNBR _ Stack&-1, At[EscD1,14]; T _ RZero, LoadPage[dvPage1], GoTo[UDiv1]; %Long Divide--(2OS,,3OS)/TOS. Double-word dividend, single-word divisor, no overflow check. The remainder is left above the Stack. dividend low in Stack; hi in RTemp divisor in T quotient appears in Stack; remainder in RTemp Timing: ~ 42.5 + (9/quotient 1) + (12/quotient 0) cycles % @LUDIV: LU _ MNBR _ Stack&-1, At[EscD1,15]; T _ Stack&-1, LoadPage[dvPage1]; UDiv1: RTemp _ T, LoadPage[opPage0], GoToP[.+1]; OnPage[dvPage1]; T _ MNBR, GoToP[.+1]; *T _ divisor OnPage[opPage0]; LU _ (RTemp) - T, Skip[ALU#0]; RTemp _ sDivZeroTrap, GoTo[P4Trap]; xfTemp _ 16C, Skip[Carry']; RTemp _ sDivCheckTrap, GoTo[P4Trap]; RTemp1 _ (Zero) - T; *Save minusdivisor T _ 31C, Task; *SALUFOP = A+A+1 SALUF _ T; *The 1st bit shifted into stack is "Don't care." Stack _ (Stack) SALUFOP T, Call[DvStart]; *Shift the high dividend while simultaneously subtracting the divisor and *adding in the bit shifted out of the low word in the previous step. T _ RTemp _ (LSh[RTemp,1]) + T + 1, Skip[R>=0]; *Shift the low dividend while bringing in the quotient bit Stack _ (Stack) SALUFOP T, GoTo[DvSub]; *q bit 1 *Subtract ok? Stack _ (Stack) SALUFOP T, UseCOutAsCIn, GoTo[DvSub,Carry]; *No--undo by adding back the divisor. Would like to simply add in the next *step (i.e., ((X+divs) lshift 1) - divs .eq. (X lshift 1) + divs), but the *carry gets screwed up. T _ RTemp1, FreezeResult; T _ RTemp _ (RTemp) - T, FreezeResult; DvSub: xfTemp _ (xfTemp) - 1, FreezeResult, GoTo[DvStart,R>=0]; Stack&+1 _ T; P4Pop: LU _ NextInst[IBuf]; Stack&-1, NIRet; *Get minusdivisor + bit shifted out of low word DvStart: T _ (RTemp1) - 1, UseCOutAsCIn, Return; *Read Overhead Byte. Error check alpha in 1..4 *Timing: 29.75 to 34.75 cycles. @ROB: T _ (NextData[IBuf]) - 1, At[EscD1,16]; T _ (Stack&-1) - T - 1; PFetch1[MDS,Stack], GoTo[moTail]; *Write Overhead Byte. Error check alpha in 1..4 *(Timing: 30.75 to 37.75 cycles). @WOB: T _ (NextData[IBuf]) - 1, At[EscD1,17]; T _ (Stack&-1) - T - 1, Call[moRet]; **Avoid long refill path ***Local cache ok here? PStore1[MDS,Stack], GoTo[moTail]; %Format of a StateVector is as follows: 0 to MaxStack-1 stack words MaxStack BrkByte,,StkP (0 => empty stack) MaxStack+1 0 for a dst LocalFrameHandle for a fault MaxStack+2 FrameSizeIndex for an allocFault Long pointer if a memFault other data if an otherFault % %Dump Stack. Save stack and set StkP to 0; also save the break byte. LOCAL+beta points at the MDS block where state is saved. Timing: 47.75 + 17/word cycles. % Esc40: @DSK: T _ SStkP, At[EscD2,0]; *SStkP .eq. (NStkP xor 377) here T _ (LSh[xfBrkByte,10]) + T; RTemp _ T, LoadPage[opPage3]; xfTemp1 _ T _ MaxStack, GoToP[.+1]; OnPage[opPage3]; *This can be any page with Tail T _ (MNBR _ NextData[IBuf]) + T; PStore1[LOCAL,RTemp], Task; T _ Sub[MaxStack!,1]C; T _ (LdF[RTemp,10,10]) - T; *xfTemp1 _ StkP _ Min(StkP+2,MaxStack) Skip[Carry]; *Skip if SStkP .gr. MaxStack xfTemp1 _ (xfTemp1) + T + 1; T _ (StkP _ xfTemp1) - 1, Call[svpop]; *Loop here with 377b in T T _ (NStkP) xor T; *T _ offset in saved Stack T _ (AllOnes) + T, Skip[ALU#0]; :IF[CacheLocals]; ************************************** xfBrkByte _ 40400C, GoTo[BLTdonex]; :ELSE; ************************************************* xfBrkByte _ 40400C, GoTo[P7Tail]; :ENDIF; ************************************************ svpop: T _ (MNBR) + T; PStore1[LOCAL,Stack]; *Write stack at alpha+StkP-1 T _ 377C, Return; %Xfer and Enable NOTE: The programmer must ensure that XE doesn't trap or fault because xfWDC would be wrong. XE is used by fixed frame trap handlers which must run with interrupts disabled. ***No error check on xfWDC decrement. (LOCAL+beta+0)^ is the two-word source link, but this is known to be not type 1, so only word 0 need be fetched. (LOCAL+beta+2)^ is the two-word destination link. Timing: (16.75-2.25)+40 = 54.5 cycles to Xfer % OnPage[xfPage1]; XEFSub: PFetch1[MDS,xfTemp]; *xfTemp/1 _ dest. link G at LOCAL+beta+2/3 T _ (RZero) + T + 1; *Bypass kludge ok PFetch1[MDS,xfTemp1]; *Dest. link byte PC T _ RSh[Cycle&PCXF,10]; PFetch1[LOCAL,xfMY], Return; *Source link *Note that NextData must precede SavePC call @XE: T _ (LOCAL) + 1, LoadPage[xfPage1], At[EscD2,1]; GoToP[.+1]; OnPage[xfPage1]; T _ (CycleControl _ CNextData[IBuf]) + T + 1, Call[XEFSub]; xfWDC _ (xfWDC) - 1, Call[SavPCinFrame]; PStore1[MDS,xfOldPC]; MemStat _ Or[EarlyXfer!,xfTypeXFER!]C, GoTo[Xfer]; *Xfer and Free. Timing: (16.75-2.25)+36 = 50.5 cycles to Xfer @XF: T _ (LOCAL) - (4C), At[EscD2,2]; xfFrame _ T, LoadPage[xfPage1]; PFetch1[MDS,xfFSI], GoToP[.+1]; OnPage[xfPage1]; T _ (LOCAL) + 1; T _ (CycleControl _ CNextData[IBuf]) + T + 1, Call[XEFSub]; T _ PCFreg, Call[xfSaveRETPC]; MemStat _ Or[FreeFrame!,EarlyXfer!,xfTypeXFER!]C, GoTo[Xfer]; *Load Stack opcode. *Timing: 16.75+40+[7x(stacksize+2)] cycles @LSK: T _ NextData[IBuf], At[EscD2,3]; *xfTemp is pointer to saved state. xfTemp _ T, LoadPage[lskPage]; T _ (xfTemp) + (MaxStack); OnPage[lskPage]; PFetch1[LOCAL,RTemp1]; *RTemp1 _ break byte,,StkP xfBrkByte _ 40400C, Task; StkP _ RZero; *Fetch Min[StkP+2,MaxStack] words to the Stack; load xfTemp1 with *Min[StkP+1,MaxStack-1] (i.e., word count - 1). T _ xfTemp1 _ Sub[MaxStack!,1]C; T _ (LdF[RTemp1,14,4]) - T; *NewStkP - (MaxStack-1) will carry when NewStkP .gr. MaxStack-2. RTemp1 _ (RTemp1) and not (360C), Skip[Carry]; xfTemp1 _ (xfTemp1) + T + 1; *xfTemp1 _ NewStkP+1 T _ xfTemp, Call[.+2]; *Loop here T _ (Zero) + T + 1, xfTemp1, GoTo[.+3,R<0]; PFetch1[LOCAL,Stack]; xfTemp1 _ (xfTemp1) - 1, Return; *Loop T _ RSh[RTemp1,10]; xfBrkByte _ (xfBrkByte) or T, LoadPage[moPage]; StkP _ RTemp1, GoToP[moTail]; *Trap if 4OS,,3OS >= 2OS,,TOS unsigned; StkP _ StkP-2. *Number - bound reverses the carry-out for bound - number - 1. *Timing = 14.5+15 cycles. @BNDCKL: T _ Stack&-2, LoadPage[opPage0], At[EscD2,4]; LU _ (Stack&+1) - T, GoToP[.+1]; *High number - bound OnPage[opPage0]; T _ Stack&-2, FreezeResult, Skip[ALU=0]; Stack&+1, FreezeResult, GoTo[BndCk1]; LU _ (Stack&+1) - T, GoTo[BndCk1]; *Low number - bound *NILCK *Timing: 23.5 cycles. **No need to worry about PFetch to the stack completing in Esc opcode. @NILCK: LU _ Stack, LoadPage[opPage0], At[EscD2,5]; NILCK1: RTemp _ sPointerTrap, DblGoTo[P4Trap,P4NoTrap,ALU=0]; *Nil Check Long (Timing: 25.5 cycles) @NILCKL: T _ Stack&-1, At[EscD2,6]; LU _ (Stack&+1) or T, LoadPage[opPage0], GoTo[NILCK1]; OnPage[opPage3]; BLTSetup: LPDest _ T, GoToP[StackLP]; *Block Transfer Long Reversed--had trap support for Trinity (10.0) but I was *told this was mandatory for Klamath (11.0) Pilot release for some reason. *[S],,[S-1] = long pointer to a destination block, [S-2] = cardinal count, *and [S-3],,[S-4] = long pointer to a source block. Transfer the block. *Timing = 45.5 + 23/word cycles. :IF[WithBLTLR]; **************************************** @BLTLR: T _ RHMask[Stack&-1], At[EscD2,7]; LPDestHi _ T, LoadPage[opPage3]; LPDestHi _ (LSh[LPDestHi,10]) + T + 1; OnPage[opPage3]; T _ Stack&-2, LoadPage[opPage1], Call[BLTSetup]; Stack&+3; LU _ Stack; BLTLR1: T _ (Stack) - 1, Skip[ALU#0]; Stack&-3, GoTo[BLTdonex]; PFetch1[LP,RTemp], Call[P7Ret]; PStore1[LPDest,RTemp]; Nop; *3 mi to allow for page fault before changing count on stack. Call[P7Ret]; Stack _ (Stack) - 1, GoTo[BLTLR1,IntPending']; *Decrement count Stack&+2, GoTo[BLTint]; :ELSE; ************************************************* @BLTLR: xfTrapParm0 _ T, LoadPage[opPage0], GoTo[moUnimpx], At[EscD2,7]; :ENDIF; ************************************************ :IF[WithBLEL]; ***************************************** %Block Equal Long--have trap support. TOS,,2OS and 4OS,,5OS are long pointers to two blocks; 3OS is a cardinal count of words to compare. If any words are different, push 0, else 1. Timing: ? + 27/true word cycles. % @BLEL: T _ RHMask[Stack&-1], At[EscD2,10]; LPDestHi _ T, LoadPage[opPage3]; LPDestHi _ (LSh[LPDestHi,10]) + T + 1; OnPage[opPage3]; T _ Stack&-2, LoadPage[opPage1], Call[BLTSetup]; Stack&+3; LU _ Stack, Call[BLEL0]; *Point at word count *Loop returns here to compare words from last iteration. T _ RTemp; LU _ (RTemp1) xor T; Stack _ (Stack) - 1, Skip[ALU=0]; *Some word is different--return 0 (false). Stack&-2 _ 0C, GoTo[P7Tail]; BLEL0: T _ (Stack) - 1, LoadPage[opPage0], Skip[ALU#0]; *All words the same--return 1 (true). Stack&-2 _ 1C, GoToP[P4Tail]; PFetch1[LP,RTemp], SkipP[IntPending']; OnPage[opPage0]; Stack&+2, GoTo[NopInt]; Nop; *Let T_ finish BLECL1: PFetch1[LPDest,RTemp1], Return; %Block Equal Code Long--have trap support. TOS,,2OS is long pointer, 3OS a cardinal word count, and 4OS a cardinal offset relative to CODE. If any words of the two blocks are different, push 0, else 1. Timing: 14.5+6+?+4+(8 to true exit, 34 to false exit) + 29/true word cycles. % @BLECL: T _ RHMask[Stack&-1], At[EscD2,11]; LPDestHi _ T, LoadPage[opPage3]; LPDestHi _ (LSh[LPDestHi,10]) + T + 1; OnPage[opPage3]; T _ Stack&-2, Call[StackLPDest2]; T _ (Stack&+1) - 1; *T _ CODE offset - 1 LU _ Stack, Call[BLECL0]; *Test word count *Loop returns here to compare words from last iteration. T _ RTemp; LU _ (RTemp1) xor T; T _ (Stack&+1) - 1, Skip[ALU=0]; *T _ CODE offset - 1 *Some word is different--return 0 (false). Stack&-1 _ 0C, GoTo[P7Tail]; Stack _ (Stack) - 1; *T _ word count + CODE offset - 1. BLECL0: T _ (Stack) + T, LoadPage[opPage0], Skip[ALU#0]; *All words the same--return 1 (true). Stack&-1 _ 1C, GoToP[P4Tail]; PFetch1[CODE,RTemp], SkipP[IntPending']; OnPage[opPage0]; Stack&+2, GoTo[NopInt]; T _ (Stack&-1) - 1, GoTo[BLECL1]; *T _ word count - 1 :ELSE; ************************************************* @BLEL: xfTrapParm0 _ T, LoadPage[opPage0], GoTo[moUnimpx], At[EscD2,10]; @BLECL: xfTrapParm0 _ T, LoadPage[opPage0], GoTo[moUnimpx], At[EscD2,11]; :ENDIF; ************************************************ %Software (Pup) Checksum Opcode FOR i IN [0..size) DO sum _ LeftCycle[OnesAdd[sum,x[i]]]; ENDLOOP; TOS-0, Stack3: high half of pointer TOS-1, Stack2: low half of pointer TOS-2, Stack1: count (hickup if cross 64k boundary) TOS-3, Stack0: sum (must be initialized to 0) Rest of Stack must be empty % @CKSUM: T _ RHMask[Stack&-1], At[EscD2,12]; LPhi _ T, LoadPage[opPage1]; LPhi _ (LSh[LPhi,10]) + T + 1, CallP[StackLPz]; *StackLPy Returns after LP,,LPhi _ Stack2,,Stack3 with Stack popped twice, *LPhi bounds-checked and in base register format. LU _ Stack&+1, LoadPage[csPage]; GoToP[CSBeg,ALU#0]; OnPage[csPage]; CSEnd: LU _ (Stack0) xnor (0C); LoadPage[moPage], Skip[ALU#0]; Stack&-2 _ 0C, GoToP[moTail]; Stack&-2, GoToP[moTail]; *Possible page fault after next mi, so no Stack changes until it is completed. CSLoop: Dispatch[Stack2,16,2], GoTo[.+3,Carry']; LPhi _ (LPhi) + (400C) + 1; *64k boundary crossing Stack3 _ (Stack3) + 1, GoTo[.-2]; Stack2 _ T, Disp[.+1]; T _ LCy[xBuf,1], Call[CSWord], DispTable[4]; T _ LCy[xBuf1,1], Call[CSWord]; T _ LCy[xBuf2,1], Call[CSWord]; T _ LCy[xBuf3,1], Call[CSWord]; PFetch4[LP,xBuf,0], Skip; CSBeg: PFetch4[LP,xBuf,0]; LP _ (LP) or (3C); *Compute address of next quadword T _ LP _ (LP) + 1, GoTo[CSLoop,IntPending']; Stack&+1; LoadPage[opPage0]; *Earliest mi for LoadPage GoToP[NopInt]; CSWord: Stack1 _ (Stack1) - 1; Stack0 _ (LCy[Stack0,1]) + T, Skip[ALU=0]; Stack0 _ (Stack0) + 1, UseCOutAsCIn, Return; Stack0 _ (Stack0) + 1, UseCOutAsCIn, GoTo[CSEnd]; *Bit Block Transfer--code in BitBlt.Mc :IF[WithBitBlt]; *************************************** @BITBLT: T _ MDShi, LoadPage[bbp1], At[EscD2,13]; bbArgHi _ T, GoTo[MesaBitBLT]; :ELSE; ************************************************* @BITBLT: xfTrapParm0 _ T, LoadPage[opPage0], GoTo[moUnimpx], At[EscD2,13]; :ENDIF; ************************************************ *Text Block Transfer :IF[WithTextBlt]; ************************************** @TXTBLT: T _ txrArgSPtr, LoadPage[TxP1], At[EscD2,14]; txrArgLo _ T, GoTo[TextBlt]; :ELSE; ************************************************* @TXTBLT: xfTrapParm0 _ T, LoadPage[opPage0], GoTo[moUnimpx], At[EscD2,14]; :ENDIF; ************************************************ *Byte Block Transfer--have trap support. @BYTBLT: xfTrapParm0 _ T, LoadPage[opPage0], GoTo[moUnimpx], At[EscD2,15]; *Byte Block Transfer Reversed--have trap support. @BYTBLTR: xfTrapParm0 _ T, LoadPage[opPage0], GoTo[moUnimpx], At[EscD2,16]; %Returns 32d-bit result with information about the microcode. [S]: Day of release encoded as number of days since 1 January 1901 [S-1]: Bits 0:3 Engineering number (1 = Alto I, 2 = Alto II without extended memory, 3 = Alto II with extended memory, 4 = Dolphin, 5 = Dorado, 6 = Dandelion, 7 = Dicentra; these assignments are historical from the Alto VERS opcode). Bits 4:7 Version number mod 16d Bits 8:15 Flags: Bit 14 1 = have floating point microcode Bit 15 1 = have Cedar microcode Pilot time is a long cardinal equal to the number of seconds since midnight 1 January 1901. This opcode pushes the number of days since 1 Jan 1901; to convert to Pilot time, lengthen the result and multiply by 86,400. For the macros below, 1904, 1908, ..., 1980, 1984, etc. are leap years. So 1 January 1982 is 81*365 + 19 days = 29584 days (=71620b) after 1 January 1901; 365d = 555b. % Macro[MakeYear,Set[YearOffset, Add[71620,Select[Sub[#1,122],0,555,1332,2110,2665,3442,4217,4775]]] Set[LeapOffset,Select[Sub[#1,122],0,0,1,0,0,0,1,0]] ]; Macro[MakeDay,Set[DayOffset,Sub[#1,1]]]; Macro[MakeMonth,Set[MonthOffset, IFG[#1,6,Select[Sub[#1,7],265,324,363,421,460,516], Select[Sub[#1,1],0,37,73,132,170,227]]] IFG[MonthOffset,72,Set[MonthOffset,Add[LeapOffset,MonthOffset]]] ]; Set[VersionNumber,1]; MakeYear[124]; *84 MakeMonth[5]; *May MakeDay[25]; *21 Set[VersionFlags,Add[40000, LShift[VersionNumber,10], WithCedar, LShift[WithFLoatingPoint,1] ]]; Set[ReleaseDate,Add[YearOffset,MonthOffset,DayOffset]]; @VERSION: Stack&+1 _ HiA[VersionFlags], At[EscD2,17]; Stack _ (Stack) or (LoA[VersionFlags]); Stack&+1 _ HiA[ReleaseDate]; Stack _ (Stack) or (LoA[ReleaseDate]), GoTo[moTail]; %Esc60: *Double Multiply. Have trap support. *DMUL multiplies two 32-bit integers and returns a 32-bit integer. If the *quotient exceeds 32 bits, the high-order 32 bits are discarded. (???) @DMUL: xfTrapParm0 _ T, LoadPage[opPage0], GoTo[moUnimpx], At[EscD3,0]; *Signed Divide--have trap support. @SDIV: xfTrapParm0 _ T, LoadPage[opPage0], GoTo[moUnimpx], At[EscD3,1]; *Signed Double Divide. Have trap support. *SDDIV divides two 32-bit integers and returns the 32-bit quotient; the *32-bit remainder is left above TOS. Remainder has same sign as dividend? @SDDIV: xfTrapParm0 _ T, LoadPage[opPage0], GoTo[moUnimpx], At[EscD3,2]; *Unsigned Double Divide. Have trap support. *UDDIV is same as SDDIV using cardinals instead of integers. @UDDIV: xfTrapParm0 _ T, LoadPage[opPage0], GoTo[moUnimpx], At[EscD3,3]; e12(1792)\f2 @ESC64: xfTrapParm0 _ T, LoadPage[opPage0], GoTo[moUnimpx], At[EscD3,4]; @ESC65: xfTrapParm0 _ T, LoadPage[opPage0], GoTo[moUnimpx], At[EscD3,5]; @ESC66: xfTrapParm0 _ T, LoadPage[opPage0], GoTo[moUnimpx], At[EscD3,6]; @ESC67: xfTrapParm0 _ T, LoadPage[opPage0], GoTo[moUnimpx], At[EscD3,7]; @ESC70: xfTrapParm0 _ T, LoadPage[opPage0], GoTo[moUnimpx], At[EscD3,10]; @ESC71: xfTrapParm0 _ T, LoadPage[opPage0], GoTo[moUnimpx], At[EscD3,11]; @ESC72: xfTrapParm0 _ T, LoadPage[opPage0], GoTo[moUnimpx], At[EscD3,12]; @ESC73: xfTrapParm0 _ T, LoadPage[opPage0], GoTo[moUnimpx], At[EscD3,13]; @ESC74: xfTrapParm0 _ T, LoadPage[opPage0], GoTo[moUnimpx], At[EscD3,14]; @ESC75: xfTrapParm0 _ T, LoadPage[opPage0], GoTo[moUnimpx], At[EscD3,15]; @ESC76: xfTrapParm0 _ T, LoadPage[opPage0], GoTo[moUnimpx], At[EscD3,16]; @ESC77: xfTrapParm0 _ T, LoadPage[opPage0], GoTo[moUnimpx], At[EscD3,17]; % *Alpha = 100b-117b are single precision floating point in MesaFP.Mc *Alpha = 120b-137b are reserved for other floating point (?) *Alpha = 140b-157b are Cedar opcodes in CedarGC.Mc. Esc160: *Write 16-bit current process @WRPSB: T _ Stack&-1, At[EscD7,0]; prCurrentPsb _ T, Return; *Write MDS @WRMDS: T _ Stack&-1, LoadPage[wrMDSPage], At[EscD7,1]; MDShi _ T, GoToP[.+1]; OnPage[wrMDSPage]; *Call here from MesaP. WRMDS1: T _ MDShi _ (LSh[MDShi,10]) + T; LOCALhi _ T; GLOBALhi _ T, Return; *Write Wakeups Pending; know that RSImage and NWW are consecutive locations. @WRWP: RTemp _ IP[RSImage]C, At[EscD7,2]; LU _ MNBR _ Stack&-1, Call[moStkPSave]; LU _ MNBR; T _ Stack _ (Stack) or (IntPendingBit), Skip[ALU#0]; T _ Stack _ (Stack) and not (IntPendingBit); RS232 _ T, GoTo[moMNBRWRx]; *Write Wakeup Disable Counter (writing with 177777b doesn't work) @WRWDC: T _ (Stack&-1) + 1, At[EscD7,3]; xfWDC _ T, GoTo[EI]; *Write Process Tick Count; writes prTicks register and initializes prTime to *3 field interrupts/tick. @WRPTC: RTemp _ IP[prTime]C, At[EscD7,4]; LU _ MNBR _ Stack&-1, Call[moStkPSave]; Stack _ 3C, GoTo[moMNBRWRx]; *prTime init DblPopWRTemp: MNBR _ Stack&-1, Task; T _ Stack&-1; *New ClockHi,,ClockLo into MNBR,,RTemp1 RTemp1 _ T, Call[moStkPSave]; T _ RTemp1; Stack _ T, GoTo[moMNBRWRx]; *Write ClockLo *Write Interval Timer @WRIT: RTemp _ IP[ClockLo]C, GoTo[DblPopWRTemp], At[EscD7,5]; *Write Xfer Trap Status @WRXTS: T _ Stack&-1, At[EscD7,6]; xfXTSReg _ T, Return; *Write Maintenance Panel @WRMP: T _ Stack&-1, LoadPageExternal[0], At[EscD7,7]; GoToExternal[PNIPStart]; *PNIPStart=IMX 176b *Push 16-bit current process @RRPSB: T _ prCurrentPsb, GoTo[moPushT], At[EscD7,10]; *Read MDS @RRMDS: T _ RSh[MDShi,10], GoTo[moPushT], At[EscD7,11]; *Read Wakeups Pending @RRWP: RTemp _ IP[NWW]C, GoTo[moPshRRTemp], At[EscD7,12]; *Read Wakeup Disable Counter @RRWDC: T _ xfWDC, GoTo[moPushT], At[EscD7,13]; ***Double precision here? *Read Process Tick Count @RRPTC: RTemp _ IP[prTicks]C, GoTo[moPshRRTemp], At[EscD7,14]; moDblPshRRTemp: T _ (SStkP&NStkP) xor (377C), Call[moStkPSwap]; *No tasking between reading ClockLo and ClockHi T _ Stack&+1; MNBR _ Stack, Call[moStkPSwap]; Stack&+1 _ T; T _ MNBR, GoTo[moPushT]; *Read Interval Timer @RRIT: RTemp _ IP[ClockLo]C, GoTo[moDblPshRRTemp], At[EscD7,15]; *Read Xfer Trap Status @RRXTS: T _ xfXTSReg, GoTo[moPushT], At[EscD7,16]; @a177: xfTrapParm0 _ T, LoadPage[opPage0], GoTo[moUnimpx], At[EscD7,17]; *200b-217b reserved for processor-dependent ESC opcodes Esc200: *Opcodes for Mesa Input/Ouput. * Stack[0:7]=XXX, Stack[10:13]=Task, Stack[14:17]=I/O register no. ***This won't work on 3MB ethernet because of H4PE's. @INPUT: T _ Stack&-1, At[EscD10,0]; Input[Stack], Return; @OUTPUT: T _ Stack&-1, LoadPage[opPage0], At[EscD10,1]; Output[Stack]; *5 mi to task, avoiding Gotcha OnPage[opPage0]; UseCTask, Call[P4Ret]; GoTo[P4Tail]; %LoadRAMJ is called with a flag word at TOS and a long pointer at 2OS,,3OS to the LoadRam table, formatted as follows: Word 0/ Version number (always has been 0) Word 3n+1/ 40:43,,addr Word 3n+2/ 0:17 Word 3n+3/ 20:37 LP,,LPhi/ point at Word 0 xfTemp1/ even for inline Refresh, odd for normal tasking refresh. RTemp1/ even to believe the starting address, odd to exit with a NextInst to the next opcode inline. Discontinuity of storage refresh is a potential problem, but since the inline refresh is about 4 times faster than normal refresh, we accept the possibility of a 25 percent longer than normal wait for refreshing some RAMs. % @LOADRAMJ: T _ (Stack&-1) xor (1C), At[EscD10,2]; *Load RAM and Jump RTemp1 _ T, LoadPage[opPage1]; *Save bits, jump complemented xfTemp1 _ T, CallP[StackLP]; *Allow tasking if not jumping **Used to test VersionID at LP+0 here. *Get jump flag (1 => no jump) RTemp _ IP[FFault]C, Call[moStkPSave]; Stack _ (Stack) and not (1C); *Set trap-on-fault in FFault LoadPageExternal[LRJpage]; StkP _ RTemp, GoToExternal[LRJStart]; @RPrinter: T _ Printer, GoTo[moPushT], At[EscD10,3]; @WPrinter: Printer _ Stack&-1, Return, At[EscD10,4]; *Read & Write Ram format: * Stack=40:43,,addr, (Stack-1)=40:43, (Stack-2)=0:17, (Stack-3)=20:37. @READRAM: T _ Stack&-1, LoadPage[xfPage1], At[EscD10,5]; RTemp _ T; OnPage[xfPage1]; T _ 1C, Call[CSRead]; *Read 20:37 T _ 0C, Call[CSRead]; *Read 0:17 T _ 3C, Call[CSRead]; *Read 40:43 T _ RTemp; Stack _ (LSh[Stack,14]) or T, GoTo[xfTail]; *Subroutine CSRead reads control store for ReadRam Opcode. CSRead: APCTask&APC _ RTemp; ReadCS; *Successor of ReadCS must be even to avoid smashing return link. T _ CSData, GoTo[xfPushTR], DispTable[1,1,0]; *NOTE: can start arbitrary task with JRAM; code which is called may Return *to execute next Opcode @JRAM: APCTask&APC _ Stack&-1, GoTo[moRet], At[EscD10,6]; *Alpha = 207b CCOPR in MesaIO.Mc *Alpha = 210b FPOPR in MesaIO.Mc @STARTIO: T _ Stack&-1, LoadPageExternal[StartIOPage], At[EscD10,11]; RTemp1 _ (Zero) xnor T, GoToExternal[StartIOLoc]; *Alpha = 212b DESOPR in MesaIO.Mc %READR pushes the current value of any RM register. At entry, TOS is the octal address of the register. At exit, this has been replaced by the value of the register. NWW (357b), xfWDC (076b), prTicks (355b), and xfXTSReg (077b) could also be read by this opcode, but they want to be referenced by machine-independent opcodes given earlier. This means that only the following Dolphin-specific registers are of interest: 344b xPageCount Count of 'good' pages from Initial microcode 345b xStorageFaults Sum of (2^bad board no.) from Initial 346b xHardBadPages Count of hard bad pages from Initial 347b xSoftBadPages Count of soft bad pages from Initial 323b vCrystal Speed of system clock as function of crystal speed and tick rate: 2*mHz at 2560 cycle period, 4*mHz at 1280 cycle period, 8*mHz at 640 cycle period. Default is 320, (representing 8*40 mhz) or 1 ticks/640 cycles at 40 mhz clock, equivalent to 1 tick/64 microseconds. Currently envisioned values are as follows: 640 1280 2560 cycles/tick 40 mhz 320 160 80 44.5 356 178 89 50 400 200 100 % @READR: T _ Stack&-1, At[EscD10,13]; RTemp _ T, GoTo[moPshRRTemp]; %0S contains the value which is the argument for LoadTimer. 1S specifies the interrupt mask for naked notifies when the timer goes off. The argument for LoadTimer has the following fields: 0:3 new state Normally this will be state 5 ("simple timer") 4:11d new data Specifies the timer period in 12:15d slot number This should specify slot 16b for single-stage timers; I think 14b to 16b are free for multistage timers, provided the interrupt always occurs for slot 16b. % @USERTIMER: LoadTimer[Stack&-1], At[EscD10,14]; RTemp _ Or[And[IP[TimerInts],360],And[Sub[IP[TimerInts],1],17]]C; LU _ MNBR _ Stack&-1, Call[moStkPSave]; *Jump here to init prTicks (at prTime+1), NWW (at RSImage+1), and ClockHi *(at ClockLo+1); fall through to init TimerInts. moMNBRWRx: T _ MNBR; Stack&+1 _ T, Call[moStkPSwap]; moTail: LU _ NextInst[IBuf]; moTailx: NIRet; xfTrapParm0 _ T, LoadPage[opPage0], GoTo[moUnimpx], At[EscD10,15]; :IF[WithTMS1000]; ************************************** @SETTIME: *TMS 1000 code LU _ MNBR _ Stack&-1, At[EscD10,16]; RTemp _ IP[RSImage]C, Call[moStkPSave]; T _ MNBR, Skip[R>=0]; Stack _ T _ (Stack) or T, LoadPage[opPage1], Skip; Stack _ T _ (Stack) and not T, LoadPage[opPage1]; StkP _ RTemp, RS232 _ T, GoToP[.+1]; OnPage[opPage1]; Skip[TimeOut]; Stack&+1 _ 0C, GoTo[P5Tail]; Stack&+1 _ 100000C, GoTo[P5Tail]; :ELSE; ************************************************* @SETTIME: xfTrapParm0 _ T, LoadPage[opPage0], GoTo[moUnimpx], At[EscD10,16]; :ENDIF; ************************************************ *Alpha = 217b-377b undefined :END[MesaESC]; \f2