:TITLE[MesaX]; % Ed Fiala 2 May 1983: 2 cycle improvement at MapLPx+1. Ed Fiala 13 October 1982: Add PCB odd check at TrapInXfer; fix xfMY for LoadState opcodes; fix PC backup bug in TrapInXfer. Ed Fiala 13 May 1982: Change to @VERSION. Ed Fiala 11 March 1982: Replace D0Stuff by READR; fix InitEnd; change to BitBlt. Ed Fiala 19 February 1982: Fixed XferFixup resumption problems; shrank @LFCB, BLTLbump, and xfT1 by 1 mi each; rearranged Xfer dispatch; fix bug in interrupts requesting but disabled at BLTloop; abbreviate LoadRAMandJump opcode (no longer checks version); add LocalBlkZ, LongBlkZ, and Version for Cedar; eliminate MiscRet. Ed Fiala 7 October 1981: Added 13b mi on page 10 (moPage) to setup this page for general use by Mesa and reference prTime and prTicks through StkP; save 6 mi elsewhere; enlarged MISC dispatch; add WithTextBlt and WithFloatingPoint conditionals; fix tasking problems in xfer exit, indirect xfer, others; move MIPend from here to MesaLS; fix page fault problems in xfGo, LoadState, CSum; move Misc 14b to MesaIO.Mc; change to StartIO. Ed Fiala 28 April 1981 Deleted MIntTest, saved 1 mi at InitEnd and 1 mi at xfGo1; changed MIPend to reflect NWW move out of emulator RM area to RSImage+1 and to assume NWW .ne. 0 at entry. Ed Fiala 24 March 1981 added CedarMode and CacheLocals conditionals; rewrote Xfer and its subrs to improve timing of EFC+RET about 146 cycles and of LFC+RET by about 154 to 156 cycles (timing of EFC+RET now ~301, of LFC+RET now ~209 to 211 cycles); improved @LLKB, @ALLOC, @FREE, @CATCH; @DESCB/S, and InitEnd. Ev Neely January 22, 1981 2:39 PM Fault Notification. Ed Fiala implement JRAM, trap Misc 20-77 at SD 5. Ev Neely October 6, 1980 1:04 PM: Convert to ucode TextBlt. Johnsson September 29, 1980 9:54 AM - trap fixup Jim Frandeen September 22, 1980 3:27 PM: Fix Xfer Trap. Jim Frandeen September 18, 1980 10:21 AM: Fix dispatch on RR and WR. Jim Frandeen September 16, 1980 3:50 PM: New GFT format. Jim Frandeen September 14, 1980 8:37 AM: Delete fetch of WW from 452. Add Register 0 to RR and WR inst to load CurrentPsb. Add Register 10 to RR and WR for PCTreg (process tick count). Delete use of IntType. Replace PC/PChi refs by PCB/PCBhi. Delete Alto kludge at DWDC. Johnsson August 1, 1980 11:56 AM - Xfer trap and trap pc's Jim Frandeen July 21, 1980 11:38 AM: Implement GetF (Get Flags). Add TextBlt as unimplemented instruction. Jim Frandeen July 16, 1980 1:36 PM: Change use of AC2 by BitBlt. Jim Frandeen July 7, 1980 10:18 AM: Check all 32 bits of base registers instead of FixVA. HGM June 29, 1980 12:22 AM, changes for XWire, Add CheckSum, use pRSImage rather than 342c Johnsson June 16, 1980 9:48 AM, Mesa6 procdesc, PrincOps traps Johnsson January 28, 1980 12:20 PM, remove LRJ, external refs Jim Frandeen January 22, 1980 11:22 AM: cleanup for D0Lang Version 6. NOTES: 1) Something better for CODEhi out of bounds at Loadgc2? % *since xfPage1 has NextData's and NextInsts, it must have refill link at 377 xfRefill: PFetch4[PCB,IBuf,4], GoToP[MesaRefill], At[LShift[xfPage1,10],377]; SaveRLink: xfRLink _ T, Return; xfRet: Return; *End of initialization and start of emulators (LoadRAM, called from *Initialize, jumps here). InitEnd: *StkP contains IP[FFault]; set "trap on page fault" Stack _ (Stack) or (1C), At[InitEndLoc]; LoadPage[xfPage1]; StkP _ RZero, GoToP[Xfer]; OnPage[opPage3]; P7StkPSave: T _ (SStkP&NStkP) xor (377C); StkP _ RTemp, RTemp _ T, NoRegILockOK, Return; %-------------------------------------------------------------- Xfer input registers xfMX dest link or indirect link xfBrkByte 40400b + break bytecode to execute xfXTSReg Xfer trap flag xfFSI frame size index xfFrame pointer to head-of-list for current frame if freeing it. xfMY possible trap parameter MemStat possible FreeFrame, Trap, or NoPushSD bits set temporaries xfCount, xfTemp-1, xfTemp, xfTemp1, RTemp, RTemp1, xBuf Page faults are dealt with in three steps: (1) Bytecodes that page fault prior to setting EarlyXfer in MemStat will be restarted after fault service. (2) A page fault with EarlyXfer will rebuild LOCAL, CODE/CODEhi, and GLOBAL from the frame pointed to by MNBR; then as in (1) above. (3) XferFixup in MemStat indicates that all references which might page fault in the old context are complete; if the PFetch4 which refills IBuf faults, IBuf will be filled with 377 bytecodes and the fault handler will continue Xfer; bytecode 377 microcode (illegal in normal programs) then deals with the trap. The stack must not be smashed until page faults in step (2) above are impossible. Also, the page fault handler smashes SALUF. It would be nice to advance the references at xfT0, xfT0Local-1, and Loadgc0+2, but this seems not to work because any fetch in page 0 causes an address fault. --------------------------------------------------------------- % OnPage[xfPage1]; *Enter here from LoadState, efcr, @SFC, BackPCandTrap, and BackTrap. SavePCXfer: T _ LSh[CODE,1]; T _ (LSh[PCB,1]) - T, GoTo[XferNoStorePC,R Odd]; T _ (PCFreg) + T; xfTemp _ T; StorePCTrap1: *Enter here from StorePCTrap. PStore1[LOCAL,xfTemp,1]; *Can't fault XferNoStorePC: T _ LOCAL, Task; xfMY _ T; %Timing to here: 22 cycles (frame link) or 23 (code link) on EFC 26.25 cycles (frame link) to 27.25 (code link) on EFCB 15 cycles on RET 19 cycles on SFC type 0, 23 on SFC type 1 42 cycles on PORTO type 0, 39 on type 1 % *Enter here directly from InitEnd, LoadState, @RET, and @PORTO. Xfer: LU _ Dispatch[xfMX,16,2]; T _ xfMX, Disp[.+1]; *T points at frame being reentered; get GFTP and saved PC. xfDisp: MNBR _ LOCAL, DblGoTo[xfT0,xfCF,ALU#0], DispTable[4]; xfCount _ T, GoTo[xfT1]; *Save descriptor PFetch1[MDS,xfTemp], GoTo[xfT2]; xfCount _ T, GoTo[xfT1]; xfCF: T _ xfMY; RTemp _ sControlFault, GoTo[SetTrapParmXfer]; xfT0: PFetch2[MDS,xfTemp-1], OddOK; MemStat _ (MemStat) or (EarlyXfer), Call[TtoLOCAL]; LU _ (MemStat) and (Trap); T _ GLOBAL, GoTo[.+3,ALU=0]; *This is a poor place to task but avoids long path. PStore2[LOCAL,xfMY,2], Call[xfRet]; *New frame _ xfMY, TrapParm T _ (Form-4[xfTemp-1]) xor T, Skip; *Equal old and new GLOBAL implies equal CODE, CODEhi, PCBhi, and *xfGFIWord, so Loadgc need not be called. Type 1 Xfers don't need *this improvement because local function calls are used. T _ (Form-4[xfTemp-1]) xor T; GLOBAL _ (GLOBAL) xor T, GoTo[xfGo,ALU=0]; Skip[ALU#0]; RTemp _ sUnbound, GoTo[TrapInXfer]; PFetch4[GLOBAL,xfGFIWord,0], NonQuadOK, Call[Loadgc1]; *Free the old frame if FreeFrame=1 in MemStat; new byte pc in xfTemp *NoPushSD true on traps, LST, and LSTF only, FreeFrame on RET and LSTF. xfGo: LU _ Dispatch[MemStat,10,2]; *FreeFrame & NoPushSD bits PCF _ xfTemp, Disp[.+1]; T _ xfFSI _ (xfFSI) + (xfAV), Call[FreeSub0], At[xfMSTab,3]; MemStat _ XferFixup, GoTo[xfGo1]; T _ xfFSI _ (xfFSI) + (xfAV), At[xfMSTab,2]; PFetch1[MDS,xBuf], Call[FreeSub1]; T _ xfMX, GoTo[xfGo0]; T _ xfMX, At[xfMSTab,0]; xfGo0: Stack&+1 _ T; T _ xfMY, Call[StackGetsT]; Stack&-2; MemStat _ XferFixup, At[xfMSTab,1]; xfGo1: xfXTSReg _ RSh[xfXTSReg,1], GoTo[XferTrap,R Odd]; ***BUG here T _ RSh[xfTemp,1]; PFetch4[CODE,IBuf]; %NOTE: if an MC1 fault happens with XferFixup true in MemStat, Fault.Mc will resume at this mi with CODE+RSh[xfTemp,1] in T, simulating the bypass kludge, and with -1 in PCF[IBuf]. This won't work if faults can happen on any of the references by FreeSub or on the local cache refill reference below, but FreeSub's references won't fault and the local cache refill won't fault because LOCAL+7 must be on the same page with LOCAL+0. % PCB _ T, LoadPage[BrkBPage], At[xfFaultGoLoc]; *bypass kludge PCB _ Form-4[PCB]; OnPage[BrkBPage]; :IF[CacheLocals]; ******************************** PFetch4[LOCAL,LocalCache0,4]; :ENDIF; ****************************************** T _ 40400C; %xfBrkByte is offset by 2001b rcy 2, so when it contains 40400b no break byte is pending. Interrupts must be prevented between Xfer and the following bytecode, which might read a trap status register or disable interrupts, so exit with NextInst/NIRet is allowed only when IntPending is false. Refill is impossible since IBuf was just refilled. % LU _ (xfBrkByte) - T, GoTo[NormalGo,IntPending']; *IntPending--manually dispatch next bytecode to avoid interrupt. *Skip if real break byte. T _ CNextData[IBuf], Skip[ALU#0]; xfBrkByte _ (xfBrkByte) or T; *Important to task; cycles here add to those of the next opcode. DoBreakByte: MemStat _ Normal, Task; xfBrkByte _ LCy[xfBrkByte,2]; APCTask&APC _ xfBrkByte; xfBrkByte _ 40400C, Return; %Regular dispatch works when IntPending is false. Approximate timing through NIRet below: 109 cycles on LFC 171 cycles on EFC (type 1) 102 cycles on local RET 130 cycles on external RET (type 0) +6 cycles if CacheLocals is true. % NormalGo: LU _ CNextInst[IBuf], Skip[ALU#0]; MemStat _ Normal, NIRet; GoTo[DoBreakByte]; OnPage[xfPage1]; xfT1: T _ xfGFT; T _ (LdF[xfCount,0,12]) + T; *T _ gfi + xfgft PFetch1[MDS,xfTemp]; MNBR _ LOCAL, Call[MemEarlyXfer]; * 2*evi from descriptor xfCount _ (xfCount) and (76C), Call[Loadgc]; *Loadgc did xfTemp _ (xfCount) + ((xfTemp) & 3) lshift 6) + 2 ***Moving this Task 1 mi later would be better. T _ xfTemp, Task; *xfTemp,xfTemp1 _ wordpc,FSI word. PFetch2[CODE,xfTemp]; *Might page fault *Enter here on LFC; allocate new frame and patch links. Unnecessary to enter *EarlyXfer state if LOCAL not smashed until Alloc fault is impossible below. XferGt: T _ xfAV; T _ (RHMask[xfTemp1]) + T; *Timing to here = 31.0 cycles on LFC, 37.25 on LFCB. PFetch1[MDS,xfTemp1]; *Head-of-list (can't fault) xfTemp-1 _ T, Call[TtoxfRSAV]; *Indirect allocate returns here LU _ LdF[xfTemp1,16,1], GoTo[XferGt0,R Even]; *Alloc failed. Cause FrameFault with destination as parameter. *To share backup code the first part of the FrameFault is treated as *a trap. RTemp is set negative to allow FrameFaults to be separated *at StorePCTrap. MNBR _ LOCAL is redundant on EFC but necessary on LFC. MNBR _ LOCAL; T _ (xfTemp-1) - (xfAV); RTemp _ 100000C, GoTo[SetTrapParmXfer]; XferGt0: xfTemp1 _ T _ Form-4[xfTemp1], GoTo[XferGt1,ALU=0]; xfTemp1 _ RSh[xfTemp1,2]; *Indirect T _ (xfTemp1) + (xfAV); PFetch1[MDS,xfTemp1]; TtoxfRSAV: xfRSAV _ T, Return; *Alloc succeeded--fetch word 0, pointer to next free frame in chain *This is the last reference which can page fault. XferGt1: PFetch1[MDS,RTemp]; xfTemp _ LSh[xfTemp,1]; *store accesslink and Returnlink PStore4[MDS,GLOBAL], Call[TtoLOCAL]; T _ xfRSAV; *This reference can't fault. PStore1[MDS,RTemp], GoTo[xfGo]; *Complete frame allocation xfT2: Call[xfRet]; LU _ Dispatch[xfTemp,16,2]; T _ xfTemp, Disp[xfDisp]; MemEarlyXfer: MemStat _ (MemStat) or (EarlyXfer), Return; TtoLOCAL: LOCAL _ T, Return; %-------------------------------------------------------------- Loadgc load global pointer and code pointer given local pointer or GFT pointer input registers xfTemp global frame address output registers CODE,CODEhi code base register GLOBAL global base register xfTemp modified for Xfer type 1 during memory wait --------------------------------------------------------------- % *CallExternal to Loadgc from Fault.Mc, Xfer type 1, and TrapInXfer; to *Loadgc1 from Xfer type 0. *Fill xfGFIWord, CODE, and CODEhi with new global overhead; the *RM register above CODEhi (xBuf) is smashed; modifications to xfTemp *are for the call from Xfer type 1. Loadgc: T _ Form-4[xfTemp], At[LoadGCLoc]; *xfPage1 xfTemp _ LdF[xfTemp,16,2], Skip[ALU#0]; RTemp _ sUnbound, GoTo[TrapInXfer]; PFetch4[MDS,xfGFIWord], NonQuadOK; GLOBAL _ T; T _ (xfCount) + 1; xfTemp _ (LSh[xfTemp,6]) + T + 1; * 2*evi + 2 Loadgc1: LU _ CODE, LoadPage[LoadgcPage], GoTo[Loadgc2,R Even]; T _ xfMX, LoadPage[xfPage1], GoToP[.+1]; OnPage[LoadgcPage]; RTemp _ sCSegSwappedOut, GoToP[SetTrapParmXfer]; *Test for bad pointer OnPage[xfPage1]; Loadgc2: LU _ RSh[CODEhi,6], GoToP[.+1]; OnPage[LoadgcPage]; CODEhi _ T _ LdF[CODEhi,12,6], Skip[ALU=0]; T _ CODEhi _ (Zero) - 1, Skip; *Code doesn't cross 64K boundary T _ CODEhi _ (LSh[CODEhi,10]) or T; PCBhi _ T, Return; %-------------------------------------------------------------- FreeSub free's a frame. None of FreeSub's memory references can page fault because av must be resident and L[-1] must not be swapped out. Also, L[0] must be quadaligned and at least 5 words long (The local cache imposes an additional constraint if frames are not at least 8 words long). input registers T pointer to frame xfFSI pointer to head-of-list temps xfFrame frame pointer xBuf frame chain link --------------------------------------------------------------- % OnPage[xfPage1]; FreeSub: xfFrame _ T; xfFSI _ T _ (xfFSI) + (xfAV); *Xfer enters here rather than at FreeSub. FreeSub0: PFetch1[MDS,xBuf]; *get head of list from av FreeSub1: xfFrame _ T _ (xfFrame) + 1; PStore4[MDS,xBuf]; *link _ head T _ xfFSI; PStore1[MDS,xfFrame], Return; *head _ frame pointer SavePCFirst: *if frame would have been freed, must save PC PFetch1[LOCAL,xfTemp,0], Call[Loadgc]; *restore smashed CODE LoadPage[opPage3]; MemStat _ (MemStat) and not (FreeFrame), Call[SavPCinFrame]; *Enter here from Loadgc or type 0 Xfer if unbound and from SetTrapParmXfer. TrapInXfer: T _ MNBR, Call[TtoLOCAL]; LU _ (MemStat) and (FreeFrame); PFetch1[LOCAL,xfTemp,1], GoTo[SavePCFirst,ALU#0]; %It might be possible to get here on CSegSwappedOut trap (start trap) with PCB odd; in other words, the Xfer call from MesaP is always type 0 to an existing frame, so Xfer alloc and control traps are impossible, but a start trap could happen, so must check for PCB odd here. % PCB, Skip[R Odd]; T _ (PCXreg) - 1, Call[xfFixPCStkP]; *RTemp is < 0 here only on Xfer Allocate failure. StorePCTrap: RTemp _ (RTemp) + (xfAV), GoTo[FrameFault,R<0]; T _ (RTemp) + (xfSDOffset); PFetch1[MDS,xfMX], Call[xfRet]; MemStat _ Or[Trap!,NoPushSD!]C, GoTo[StorePCTrap1]; *Restore StkP to beginning of inst (SFC & PORTO) and backup PC in xfTemp by *PCF - [(PCX-1) mod 10b]. xfFixPCStkP: T _ (PCFreg) - T, Skip[ALU>=0]; T _ 7C, GoTo[.-1]; xfTemp _ (xfTemp) - T, Skip[ALU>=0]; *crossed quad boundary in opcode. xfTemp _ (xfTemp) - (10C); T _ SStkP; RTemp1 _ T; StkP _ RTemp1, Return; *Enter here from xfGo1 if xfXTSReg was odd. XferTrap: T _ xfMX, Task; TrapParm _ T; RTemp _ sXferTrap, GoTo[StorePCTrap]; *Frame faults are handled by Fault Notification FrameFault: PStore1[LOCAL,xfTemp,1], Task; T _ TrapParm; *(NOTE: IP[prData] .eq. IP[xfMY], and xfMY smashed by SavPCinFrame, *so can't do this earlier.) prData _ T, LoadPage[opPage0]; FrameFault1: *Also jump here on ALLOC failure T _ qFrameFaultOs, GoToP[.+1]; OnPage[opPage0]; *PCB is made odd so that when ReSchedule calls SavPCinFrame, the PC *won't be saved. PCB _ 1C, GoTo[prFault]; *In MesaP OnPage[xfPage1]; *ControlTrap, CSegSwappedOut or start trap (from Loadgc), and Xfer Alloc trap *come here SetTrapParmXfer: TrapParm _ T, GoTo[TrapInXfer]; %-------------------------------------------------------------- SaveState saves state and zeroes StkP for DST, MesaP, and ? input registers xfTemp where to save state +0 to +MaxStack-1 stack +MaxStack StkP +MaxStack+1 LOCAL temporaries xfRlink Return-to address xfTemp1 set StkP to this depth and pop till empty xfTemp2 StkP stored from here DST saves xfMY at MaxStack+2 after SaveState returns. --------------------------------------------------------------- % SaveState: * UseCTask in calling instruction T _ APCTask&APC, Call[SaveRLink]; *save link in rlink T _ (xfTemp) + (Add[MaxStack!,1]C); PStore1[MDS,LOCAL], Call[sv377]; T _ (NStkP) xor T; *true Stack pointer to T xfTemp2 _ T; T _ (xfTemp) + (MaxStack), Task; PStore1[MDS,xfTemp2]; *xfTemp1 _ Min(StkP+2,MaxStack) T _ (xfTemp2) - (Sub[MaxStack!,1]C); xfTemp1 _ MaxStack, Skip[Carry]; xfTemp1 _ (xfTemp1) + T + 1; T _ (StkP _ xfTemp1) - 1, Call[svpop]; *Loop Returns here T _ (NStkP) xor T; T _ (AllOnes) + T, Skip[ALU#0]; * T _ offset in saved Stack APCTask&APC _ xfRlink, GoTo[xfRet]; svpop: T _ (xfTemp) + T; PStore1[MDS,Stack]; sv377: T _ 377C, Return; %-------------------------------------------------------------- LoadState loads state for LSTF and LST. input registers xfTemp where to load state from MemStat preserved; FreeFrame bit is checked on exit output registers xfMY source link xfMX dest link xfBrkByte break instruction replacement temp registers xfTemp1 count of Stack items to be loaded --------------------------------------------------------------- % LoadState: T _ (xfTemp) + (MaxStack); PFetch1[MDS,IBuf]; xfBrkByte _ 40400C, Task; T _ (xfTemp) + (Add[MaxStack!,1]C); PFetch1[MDS,xfMX]; T _ (xfTemp) + (Add[MaxStack!,2]C); StkP _ RZero; PFetch1[MDS,xfMY], Task; T _ xfTemp1 _ Sub[MaxStack!,1]C; *Check for MaxStack-1 or MaxStack, T _ d - (MaxStack-1) T _ (LdF[IBuf,14,4]) - T; IBuf _ (IBuf) and not (360C), Skip[Carry]; *Stack depth + 2 = MaxStack+(d-(MaxStack-1))+1 xfTemp1 _ (xfTemp1) + T + 1; T _ (xfTemp) - 1, Call[.+1]; *Loop here T _ (Zero) + T + 1, xfTemp1, GoTo[.+3,R<0]; PFetch1[MDS,Stack]; xfTemp1 _ (xfTemp1) - 1, Return; *Loop T _ RSh[IBuf,10]; xfBrkByte _ (xfBrkByte) or T; StkP _ IBuf, GoTo[Xfer]; MesaRefill7: PFetch4[PCB,IBuf,4], GoToP[MesaRefill], At[3777]; *Normally, save CODE-relative PC in frame and put Xfer source in *xfMY using RTemp1 as a temporary. CODEhi .eq. PCBhi and *|PCB-CODE| < 32K, so the result fits in one word. *FrameFault, among others, makes PCB odd to prevent the call on *SavPCinFrame from storing in the Frame. SavPCinFrame: T _ LSh[CODE,1]; SavPCinF1: T _ (LSh[PCB,1]) - T, GoTo[NoStorePC,R Odd]; *15 bits, since code segments are < 32k. T _ (PCFreg) + T; *CODE-relative byte PC of bytecode to be executed when this frame next runs. RTemp1 _ T; PStore1[LOCAL,RTemp1,1]; *Can't page fault NoStorePC: T _ LOCAL; xfMY _ T, Return; @EFC0: T _ (RZero) or not (0C), GoTo[efcr], Opcode[300]; T _ (RZero) or not (1C), GoTo[efcr], Opcode[301]; T _ (RZero) or not (2C), GoTo[efcr], Opcode[302]; T _ (RZero) or not (3C), GoTo[efcr], Opcode[303]; T _ (RZero) or not (4C), GoTo[efcr], Opcode[304]; T _ (RZero) or not (5C), GoTo[efcr], Opcode[305]; T _ (RZero) or not (6C), GoTo[efcr], Opcode[306]; T _ (RZero) or not (7C), GoTo[efcr], Opcode[307]; T _ (RZero) or not (10C), GoTo[efcr], Opcode[310]; T _ (RZero) or not (11C), GoTo[efcr], Opcode[311]; T _ (RZero) or not (12C), GoTo[efcr], Opcode[312]; T _ (RZero) or not (13C), GoTo[efcr], Opcode[313]; T _ (RZero) or not (14C), GoTo[efcr], Opcode[314]; T _ (RZero) or not (15C), GoTo[efcr], Opcode[315]; T _ (RZero) or not (16C), GoTo[efcr], Opcode[316]; T _ (RZero) or not (17C), GoTo[efcr], Opcode[317]; @EFCB: T _ NextData[IBuf], Opcode[320]; T _ (RZero) or not T; efcr: xfGFIWord, LoadPage[xfPage1], Skip[R Even]; PFetch1[CODE,xfMX], GoToP[SavePCXfer]; *Code link PFetch1[GLOBAL,xfMX], GoToP[SavePCXfer]; *Frame link lfcr: PFetch2[CODE,xfTemp]; lfcr0: T _ LSh[CODE,1], Call[SavPCinF1]; LoadPage[xfPage1]; xfMX _ Zero, GoToP[XferGt]; *LFC1 - LFC16 @LFC1: PFetch2[CODE,xfTemp, 4], GoTo[lfcr0], Opcode[321]; PFetch2[CODE,xfTemp, 6], GoTo[lfcr0], Opcode[322]; PFetch2[CODE,xfTemp,10], GoTo[lfcr0], Opcode[323]; PFetch2[CODE,xfTemp,12], GoTo[lfcr0], Opcode[324]; PFetch2[CODE,xfTemp,14], GoTo[lfcr0], Opcode[325]; PFetch2[CODE,xfTemp,16], GoTo[lfcr0], Opcode[326]; T _ 20C, GoTo[lfcr], Opcode[327]; T _ 22C, GoTo[lfcr], Opcode[330]; T _ 24C, GoTo[lfcr], Opcode[331]; T _ 26C, GoTo[lfcr], Opcode[332]; T _ 30C, GoTo[lfcr], Opcode[333]; T _ 32C, GoTo[lfcr], Opcode[334]; T _ 34C, GoTo[lfcr], Opcode[335]; T _ 36C, GoTo[lfcr], Opcode[336]; T _ 40C, GoTo[lfcr], Opcode[337]; T _ 42C, GoTo[lfcr], Opcode[340]; @LFCB: T _ (MNBR _ NextData[IBuf]) + 1, Opcode[341]; T _ (MNBR) + T + 1, GoTo[lfcr]; @SFC: T _ Stack&-1, LoadPage[xfPage1], Opcode[342]; xfMX _ T, GoToP[SavePCXfer]; *Fetch destination link (at xfRetlinkoffset) @RET: PFetch1[LOCAL,xfMX,2], Opcode[343]; *Can't fault xfMY _ 0C; T _ (LOCAL) - 1, Task; PFetch1[MDS,xfFSI]; *Can't fault ***LoadPage within 3 mi after tasking is undesirable because it prevents ***LogSE from being used, even though ordinary fault can't occur here. xfFrame _ T, LoadPage[xfPage1]; MemStat _ FreeFrame, GoToP[Xfer]; @LLKB: T _ NextData[IBuf], Opcode[344]; T _ (Zero) or not T, xfGFIWord, Skip[R Even]; PFetch1[CODE,Stack], GoTo[P7Tail]; *Code link PFetch1[GLOBAL,Stack], GoTo[P7Tail]; *Frame link *xfMX,xfMY _ [TOS+1],TOS; [TOS] _ LOCAL; Xfer @PORTO: T _ (Stack&-1) + 1, Opcode[345]; PFetch1[MDS,xfMX]; xfTemp _ T, Call[SavPCinFrame]; T _ (xfTemp) - 1; ***LoadPage within 3 mi of task. xfMY _ T, LoadPage[xfPage1]; PStore1[MDS,LOCAL], GoTo[Xfer]; *[-1OS] _ 0; if -2OS .ne. 0 then [-1OS+1] _ -2OS @PORTI: Stack&+2, Opcode[346]; T _ Stack&-1; *-2OS RTemp _ T; T _ Stack&-1, GoTo[portinz,ALU=0]; *-1OS PStore1[MDS,RZero]; T _ (RZero) + T + 1; :IF[CacheLocals]; ******************************** portinz: PStore1[MDS,RTemp]; Call[P7Ret]; *Reload store-through LOCAL cache in case port was in active frame. RefillLocalCache: PFetch4[LOCAL,LocalCache0,4], GoTo[P7Tail]; :ELSE; ******************************************* portinz: PStore1[MDS,RTemp], GoTo[P7Tail]; :ENDIF; ****************************************** @KFCB: T _ NextData[IBuf], Opcode[347]; kfcr: RTemp _ xfAV, At[KFCRLoc]; RTemp _ (RTemp) + (xfSDOffset); T _ (RTemp) + T, LoadPage[xfPage1]; PFetch1[MDS,xfMX], GoTo[SavePCXfer]; @DESCB: T _ (xfGFIWord) and not (77C), Opcode[350]; descbcom: T _ (NextData[IBuf]) + T + 1; P7PushT: LU _ NextInst[IBuf]; Stack&+1 _ T, NIRet; @DESCBS: T _ (Stack&-1) + (xfGFIOffset), Opcode[351]; PFetch1[MDS,RTemp]; T _ (RTemp) and not (77C), GoTo[descbcom]; @BLT: LP _ 0C, Opcode[352]; T _ MDShi; BLTcom: LPhi _ T; *fixup: fetch => count + 1; store => source-1, dest-1, count+1 MemStat _ BltFixup, Call[P7Ret]; *Loop here Stack&-1; LU _ Stack&-1; T _ Stack&+1, GoTo[BLTdone,ALU=0]; *Get source, point to count Stack _ (Stack) - 1; *Decrement count PFetch1[LP,RTemp]; Stack&+1; *Point to dest T _ Stack&-2; *Get dest, point to source PStore1[MDS,RTemp]; Stack _ (Stack) + 1; *Increment source Stack&+2; Stack _ (Stack) + 1, GoTo[BLTint,IntPending]; *Increment dest Return; BLTdone: Stack&-2, GoTo[BLTdonex]; :IF[CacheLocals]; ******************************** BLTdonex: MemStat _ Normal, GoTo[RefillLocalCache]; BLTint: PFetch4[LOCAL,LocalCache0,4]; BLTstop: T _ (RZero) + 1, LoadPage[opPage0]; MemStat _ Normal, GoToP[NOPint]; :ELSE; ******************************************* BLTdonex: MemStat _ Normal, GoTo[P7Tail]; BLTint: T _ (RZero) + 1, LoadPage[opPage0]; BLTstop: MemStat _ Normal, GoToP[NOPint]; :ENDIF; ****************************************** @BLTL: T _ Stack&-1, Opcode[353]; LPdesthi _ T; LU _ LdF[LPdesthi,0,12]; *Test for memory out of bounds LPdesthi _ (LSh[LPdesthi,10]) + T + 1, Skip[ALU=0]; LPdesthi _ (Zero) - 1; *Cause memory out of bounds T _ Stack&-2, LoadPage[opPage1]; LPdest _ T, CallP[StackLP]; RTemp1 _ Zero; MemStat _ BltLFixup; *fixup: source+T, dest+T, count+1 Stack&+3, Call[BLTLloop]; * point to count BLTLloop: LU _ Stack; *read count, point to source lo T _ RTemp1, GoTo[BLTLdone,ALU=0]; PFetch1[LP,RTemp]; Stack _ (Stack) - 1; *decrement count RTemp1 _ (RTemp1) + 1; *increment offset PStore1[LPdest,RTemp]; GoTo[BLTLint,IntPending]; P7Ret: Return; *goes to BLTLloop BLTLdone: Stack&-3, GoTo[BLTdonex]; BLTLint: Stack&-2; Call[BLTLbump]; *wait for page fault before updating Stack Stack&+2, Call[BLTLbump]; :IF[CacheLocals]; ******************************** PFetch4[LOCAL,LocalCache0,4], GoTo[BLTstop]; :ELSE; ******************************************* T _ (RZero) + 1, LoadPage[opPage0], GoTo[BLTstop]; :ENDIF; ****************************************** BLTLbump: Stack _ (Stack) + T + 1; Stack&+1, FreezeResult; Stack _ (Stack) + 1, UseCOutAsCIn, Return; @BLTC: T _ CODE, Opcode[354]; LP _ T; T _ CODEhi, GoTo[BLTcom]; @ALLOC: T _ (Stack&-1) + (xfAV), Opcode[356]; *T _ FSI+xfAV PFetch1[MDS,xfTemp1]; *Head-of-list (can't fault) xfTemp-1 _ T, Call[Alloc0]; *Indirect allocate returns here LU _ LdF[xfTemp1,16,1], Skip[R Even]; T _ (xfTemp-1) - (xfAV), GoTo[allocrf]; *Failure xfTemp1 _ T _ Form-4[xfTemp1], GoTo[Alloc1,ALU=0]; T _ xfTemp1 _ RSh[xfTemp1,2]; T _ (xfTemp1) + (xfAV); PFetch1[MDS,xfTemp1]; Alloc0: xfRSAV _ T, Return; *Allocate succeeded; complete allocate and done. Alloc1: PFetch1[MDS,RTemp]; Stack&+1 _ T; T _ xfRSAV; PStore1[MDS,RTemp], GoTo[P7Tail]; *Allocate failed. Cause FrameFault with destination as parameter. allocrf: TrapParm _ T, LoadPage[opPage0]; *Frame size index (FSI) is param T _ (PCXreg) - 1, Call[BackPC]; Stack&+1, Call[SavPCinFrame]; T _ TrapParm, LoadPage[xfPage1]; prData _ T, LoadPage[opPage0], GoToP[FrameFault1]; @FREE: T _ (Stack&-1) - 1, LoadPage[xfPage1], Opcode[357]; PFetch1[MDS,xfFSI], CallP[FreeSub]; P7Tail: LU _ NextInst[IBuf], At[P7TailLoc]; P7Tailx: NIRet; *Increment Wakeup Disable Counter (Disable Interrupts) @IWDC: xfWDC _ (xfWDC) + 1, GoTo[P7Tail], Opcode[360]; *Decrement Wakeup Disable Counter (Enable Interrupts) @DWDC: RTemp _ IP[NWW]C, Call[P7StkPSave], Opcode[361]; *See if any interrupts LU _ Stack&-1; *Test NWW, point StkP at RSImage xfWDC _ (xfWDC) - 1, Skip[ALU#0]; StkP _ RTemp, GoTo[DWDCnone]; T _ Stack _ (Stack) or (IntPendingBit); *set IntPending StkP _ RTemp, RS232 _ T; *Dispatch by hand to allow one bytecode without interrupt DWDCnone: T _ NextData[IBuf]; xfBrkByte _ T, LoadPage[BrkBPage]; T _ xfBrkByte _ (xfBrkByte) or (40400C), GoToP[DoBreakByte]; @CATCH: SkipData, Call[P7Tail], Opcode[363]; BitBLT: T _ MDShi, LoadPage[bbp1], Opcode[365]; *PrincOps BitBlt traps bbArgHi _ T, GoTo[MesaBitBLT]; @STARTIO: T _ Stack&-1, LoadPageExternal[StartIOPage], Opcode[366]; RTemp1 _ (Zero) xnor T, GoToExternal[StartIOLoc]; *NOTE: can start arbitrary task with JRAM; code which is called may Return *to execute next Opcode @JRAM: APCTask&APC _ Stack&-1, Call[P7Ret], Opcode[367]; LU _ NextInst[IBuf], Call[P7Tailx]; @DST: T _ NextData[IBuf], Opcode[370]; ***LoadPage after buffer refill return is problem if H4PE's or LogSE. T _ (LOCAL) + T, LoadPage[xfPage1]; xfTemp _ T, UseCTask, Call[SaveState]; ***This PStore1 must be vestigial because xfMY is a temporary register ***not guaranteed to hold the source link from the last xfer??? T _ (xfTemp) + (Add[MaxStack!,2]C); PStore1[MDS,xfMY], GoTo[P7Tail]; @LST: LU _ MNBR _ NextData[IBuf], Opcode[371]; MemStat _ NoPushSD, Call[SavPCinFrame]; T _ MNBR, GoTo[LSTgo]; @LSTF: T _ (LOCAL) - 1, Opcode[372]; PFetch1[MDS,xfFSI]; xfFrame _ T; MemStat _ Or[FreeFrame!,NoPushSD!]C; T _ NextData[IBuf]; *NextData must precede SavePC call LSTgo: T _ (LOCAL) + T, LoadPage[xfPage1]; *xfTemp is pointer to saved state. xfTemp _ T, GoTo[LoadState]; @WR: T _ NextData[IBuf], Opcode[374]; ***LoadPage after buffer refill return is problem if H4PE's or LogSE. xfTemp _ T, LoadPage[moPage]; Dispatch[xfTemp,14,4]; OnPage[moPage]; T _ MNBR _ Stack&-1, Disp[.+1]; GoTo[moTail], prCurrentPsb _ T, At[moWRTab,0]; GoTo[moTail], xfWDC _ T, At[moWRTab,1]; GoTo[moTail], xfXTSReg _ T, At[moWRTab,2]; MDShi _ T, At[moWRTab,3]; T _ MDShi _ (LSh[MDShi,10]) + T; LOCALhi _ T; GLOBALhi _ T, GoTo[moTail]; RTemp _ IP[prTime]C, Call[moStkPSave], At[moWRTab,10]; Stack _ 3C; *prTime init T _ MNBR; Stack&+1 _ T, Call[moStkPSwap]; *prTicks init (at prTime+1) moTail: LU _ NextInst[IBuf]; moTailx: NIRet; moRefill: PFetch4[PCB,IBuf,4], GoToP[MesaRefill], At[LShift[moPage,10],377]; moStkPSave: T _ (SStkP&NStkP) xor (377C); moStkPSwap: RTemp _ T, StkP _ RTemp, NoRegILockOK, Return; @RR: T _ NextData[IBuf], Opcode[375]; xfTemp _ T, LoadPage[moPage]; Dispatch[xfTemp,14,4]; OnPage[moPage]; T _ (SStkP&NStkP) xor (377C), Disp[.+1]; GoTo[moPushT], T _ prCurrentPsb, At[moRRTab,0]; GoTo[moPushT], T _ xfWDC, At[moRRTab,1]; GoTo[moPushT], T _ xfXTSReg, At[moRRTab,2]; GoTo[moPushT], T _ (MDShi) and (377C), At[moRRTab,6]; RTemp _ IP[prTicks]C, Call[moStkPSwap], At[moRRTab,10]; moRestoreStkPPush: *Enter from @VERSION T _ Stack, Call[moStkPSwap]; *T _ prTicks moPushT: LU _ NextInst[IBuf]; Stack&+1 _ T, NIRet; @BRK: LoadPage[opPage0], Opcode[376]; RTemp _ Zero, GoToP[BackPCandTrap]; *Cause pagefault trap--should not occur as a bytecode. Fault.Mc fills IBuf *with 377b bytes when it wants to continue the opcode which faulted but trap *at entry to the next opcode. TrapFlap: T _ (PCFReg) - 1, Opcode[377]; *back up PCF by one RTemp _ T, LoadPageExternal[FaultPage]; PCF _ RTemp, GoToExternal[StartMemTrapLoc]; *Unused Opcodes on page 7 :IF[CedarMode]; ******************************** @BLTCL: RTemp _ 355C, GoTo[UnimpP7], Opcode[355]; @STOP: RTemp _ 362C, GoTo[UnimpP7], Opcode[362]; RTemp _ 373C, GoTo[UnimpP7], Opcode[373]; UnimpP7: LoadPage[opPage0]; TrapParm _ 0C, GoToP[UndefTrap]; OnPage[xfPage1]; MiscUnimp: *Misc traps use 400b + alpha as OpTrapTable index LoadPage[opPage0]; *Odd placement RTemp _ (RTemp) + (400C), GoToP[UndefTrap]; :ELSE; ***************************************** @BLTCL: LoadPage[opPage0], GoTo[UnimpP7], Opcode[355]; @STOP: LoadPage[opPage0], GoTo[UnimpP7], Opcode[362]; LoadPage[opPage0], GoTo[UnimpP7], Opcode[373]; UnimpP7: RTemp _ sUnimplemented, GoToP[BackPCandTrap]; OnPage[xfPage1]; MiscUnimp: LoadPage[opPage0]; *Odd placement RTemp _ sUnimplemented, GoToP[BackPCandTrap]; :ENDIF; **************************************** *MISC - extended Opcodes accessed by dispatching on alpha @MISC: T _ MNBR _ CNextData[IBuf], Call[.+2], Opcode[364]; LU _ NextInst[IBuf], CallX[P7Tailx]; RTemp _ T, LoadPage[xfPage1], Skip[H2Bit8']; TrapParm _ 0C, GoToP[MiscUnimp]; Dispatch[RTemp,11,3], GoToP[.+1]; OnPage[xfPage1]; Dispatch[RTemp,14,4], Disp[.+1]; *dispatch on second byte Disp[@ASSOC], At[MiscDisp0,0]; :UNLESS[WithFloatingPoint]; **************************** *Code in MesaFP.Mc TrapParm _ 0C, GoTo[MiscUnimp], At[MiscDisp0,1]; *Alpha .eq. 20b to 37b :ENDIF; ************************************************ TrapParm _ 0C, GoTo[MiscUnimp], At[MiscDisp0,2]; *Alpha .eq. 40b to 57b :UNLESS[WithGarbCollect]; ****************************** *Code in CedarGC.Mc TrapParm _ 0C, GoTo[MiscUnimp], At[MiscDisp0,3]; *Alpha .eq. 60b to 77b TrapParm _ 0C, GoTo[MiscUnimp], At[MiscDisp0,6]; *Alpha .eq. 140b to 157b :ENDIF; ************************************************ :IF[CedarMode]; **************************************** LoadPage[moPage], GoTo[Alpha100T], At[MiscDisp0,4]; *Alpha .eq. 100b to 117b :ELSE; ************************************************* TrapParm _ 0C, GoTo[MiscUnimp], At[MiscDisp0,4]; *Alpha .eq. 100b to 117b :ENDIF; ************************************************ TrapParm _ 0C, GoTo[MiscUnimp], At[MiscDisp0,5]; *Alpha .eq. 120b to 137b TrapParm _ 0C, GoTo[MiscUnimp], At[MiscDisp0,7]; *Alpha .eq. 160b to 177b MiscTail: LU _ NextInst[IBuf], At[MiscDisp1,20]; MiscTailx: NIRet; *Associate - TOS contains map entry, (TOS-1) contains VP which is to get it. @ASSOC: T _ Stack&-1, At[MiscDisp1,0]; xBuf _ T, Call[MapLP]; ASSOC1: XMap[LP,xBuf,0], GoTo[MiscTail]; @GETF: *Get Flags - TOS contains VP T _ LSh[Stack,10], At[MiscDisp1,16]; LP _ T, Call[MapLPx]; * Set low Base XMap[LP,xBuf,0], Call[MapPushOld]; xBuf _ T, GoTo[ASSOC1]; *Restore old flags and page @SETF: T _ Stack&-1, At[MiscDisp1,1]; xBuf _ T, Call[MapLP]; XMap[LP,xBuf,0], Call[MapPushOld]; LU _ (LdF[xBuf3,11,3]) - 1; *=0 if map entry = VACANT xBuf _ (xBuf) and (70000C), Skip[ALU#0]; *isolate new flags, ignore LogSE xBuf _ T, GoTo[ASSOC1]; *Vacant entry, use old flags, oldpage T _ (Stack) and not (170000C); *Get old page number GoTo[ASSOC1], xBuf _ (xBuf) or T; *new flags, old page *Subroutine MapPushOld puts old flags & page on TOS. *MUST NOT TASK ON RETURN (map is in a bad state). MapPushOld: T _ LSh[xBuf3,10]; *Put flags,,card,blk0 in left byte T _ xBuf1 _ (RHMask[xBuf1]) or T; *blk1,rowaddr in low byte T _ (RZero) or not T, UseCTask, GoTo[StackGetsT]; *push old flags & page *Subroutine MapLP creates a base register pair from a virtual page number for the Map Opcodes. MapLP: T _ LSh[Stack,10]; LP _ T; *Set low Base *Only LH of LPhi matters here because displacement is 0. MapLPx: T _ Stack&-1, Skip[R>=0]; LPhi _ 177400C, GoTo[xfRet]; LPhi _ T, GoTo[xfRet]; *One mi to allow LPhi to be written *Read & Write Ram format: Stack=40:43,,addr, (Stack-1)=40:43, (Stack-2)=0:17, (Stack-3)=20:37. @ReadRam: T _ LdF[Stack&-1,4,14], At[MiscDisp1,2]; *get address RTemp _ T; Call[CSRead], T _ 1C; *read 20:37 Call[CSRead], T _ 0C; *read 0:17 Call[CSRead], T _ 3C; *read 40:43 T _ RTemp; Stack _ (LSh[Stack,14]) or T, GoTo[MiscTail]; *Subroutine CSRead reads control store for ReadRam Opcode. CSRead: APCTask&APC _ RTemp; ReadCS; T _ CSData, DispTable[1,1,0]; *successor of CSOp must be even StackGetsT: Stack&+1 _ T, Return; :IF[WithTextBlt]; ************************************** @TextBlt: T _ txrArgSPtr, LoadPage[TxP1], At[MiscDisp1,15]; txrArgLo _ T, GoTo[TextBlt]; :ELSE; ************************************************* TrapParm _ 0C, GoTo[MiscUnimp], At[MiscDisp1,15]; :ENDIF; ************************************************ MC[VersionID,0]; ***No longer check version at LP[0] @LoadRamJ: T _ (Stack&-1) xor (1C), At[MiscDisp1,3]; RTemp1 _ T, LoadPage[opPage1]; *RTemp1 odd => no jump xfTemp1 _ T, CallP[StackLP]; *xfTemp1 odd => allow tasking LoadPage[moPage]; RTemp _ IP[FFault]C, CallP[moStkPSave]; Stack _ (Stack) and not (1C); *Set trap-on-fault in FFault LoadPageExternal[LRJpage]; StkP _ RTemp, GoToExternal[LRJStart]; *Opcodes for Mesa Input/Ouput. * Stack[0:7]=XXX, Stack[10:13]=Task, Stack[14:17]=I/O register no. @INPUT: T _ Stack&-1, At[MiscDisp1,5]; Input[Stack], GoTo[MiscTail]; @OUTPUT: T _ Stack&-1, At[MiscDisp1,6]; Output[Stack]; *5 mi to task, avoiding Gotcha UseCTask, Call[xfRet]; GoTo[MiscTail]; %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 % @CSum: T _ Stack&-1, LoadPage[opPage1], At[MiscDisp1,7]; LPhi _ T, LoadPage[opPage0], CallP[StackLPy]; *StackLPy Returns after LP,,LPhi _ Stack2,,Stack3 with Stack popped twice, *LPhi bounds-checked and in base register format. LU _ Stack&+1, LoadPage[moPage]; PFetch4[LP,xBuf,0], DblGoToP[CSBeg,CSEnd,ALU#0]; OnPage[moPage]; *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]; CSBeg: LP _ (LP) or (3C); *Compute address of next quadword T _ LP _ (LP) + 1, GoTo[CSLoop,IntPending']; T _ 2C, 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; CSEnd: LU _ (Stack0) xnor (0C); Skip[ALU#0]; Stack&-2 _ 0C, GoToP[moTail]; Stack&-2, GoToP[moTail]; *SetMaintenancePanel Opcode * just put value on Stack @SetMP: T _ Stack&-1, LoadPageExternal[PNIPPage], At[MiscDisp1,10]; *Task 0 resumes at the bytecode exit below the label @MISC GoToExternal[PNIPStart]; *Read realtime clock; Switch to Task 17 to read the clock @RCLK: RTemp _ Or[170000,ReadTimeLoc]C, At[MiscDisp1,11]; *Task 0 resumes at the bytecode exit below the label @MISC APCTask&APC _ RTemp, GoTo[xfRet]; SetTask[17]; ReadTime: T _ ClockLo, At[ReadTimeLoc]; Stack&+1 _ T; T _ ClockHi, GoTo[StackGetsT]; SetTask[0]; @RPrinter: T _ Printer, At[MiscDisp1,12]; Stack&+1 _ T, GoTo[MiscTail]; @WPrinter: Printer _ Stack&-1, GoTo[MiscTail], At[MiscDisp1,13]; *Misc 14 is defined in MesaIO.Mc TrapParm _ 0C, GoTo[MiscUnimp], At[MiscDisp1,17]; *********************TMS 1000 CODE **************** SetTime: LoadPage[moPage], At[MiscDisp1,4]; LU _ MNBR _ Stack&-1; OnPage[moPage]; RTemp _ IP[RSImage]C, Call[moStkPSave]; T _ MNBR, Skip[R>=0]; Stack _ T _ (Stack) or T, Skip; Stack _ T _ (Stack) and not T; StkP _ RTemp, RS232 _ T; Skip[TimeOut]; Stack&+1 _ 0C, GoTo[moTail]; Stack&+1 _ 100000C, GoTo[moTail]; *****************END TMS 1000 CODE*************** :IF[CedarMode]; **************************************** %VERSION opcode returns 32d-bit result with information about the microcode. TOS: Day of release encoded as number of days since 1 January 1968. 2OS: Bits 0:3 Engineering number (0 or 1 = Alto I, 2 = Alto II without extended memory, 3 = Alto II with extended memory, 4 = Dolphin, 5 for Dorado, 6 for Dandelion (These assignments are historical from Alto VERS opcode). Bits 4:15 Machine-dependent flags; on Dolphin: 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, 1968, 1972, 1976, 1980, 1984, etc. are leap years. So 1 January 1982 is 81*365 + 19 days = 29584 (=71620b) days 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]]] ]; Macro[MakeReleaseInfo, Set[VersionFlags, Add[40000, LShift[VersionNumber,10], IFE[CedarMode,1,1,0], IFE[WithFloatingPoint,1,2,0] ] ] Set[ReleaseDate,Add[YearOffset,MonthOffset,DayOffset]] ]; Set[VersionNumber,0]; MakeYear[122]; *82 MakeMonth[12]; *October MakeDay[13]; *11 MakeReleaseInfo[]; OnPage[xfPage1]; Alpha100T: Dispatch[RTemp,14,3], SkipP[R Even]; OnPage[moPage]; LoadPage[xfPage1], GoTo[moUnimp]; Disp[.+1]; GoTo[LocalBlkZ], DispTable[10]; *Misc 100b Stack&-1, LoadPage[opPage1], GoTo[LongBlkZ]; *Misc 102b Stack&+1 _ HiA[VersionFlags], GoTo[MicVersion]; *Misc 104b T _ Stack&-1, GoTo[ReadR]; *Misc 106b LoadPage[xfPage1], GoTo[moUnimp]; *Misc 110b LoadPage[xfPage1], GoTo[moUnimp]; *Misc 112b LoadPage[xfPage1], GoTo[moUnimp]; *Misc 114b LoadPage[xfPage1], GoTo[moUnimp]; *Misc 116b moUnimp: TrapParm _ 0C, GoToP[MiscUnimp]; *Arg on TOS is cardinal count of words in local frame to zero. LocalBlkZ: Call[.+1]; *Unnecessary to do Stack&-1 for Misc opcode *Loop here *Frame starts at LOCAL+4, so count+4-1 is displacement of last word *remaining to be zeroed; do block in reverse order. LU _ Stack; T _ (Stack) + (3C), Skip[ALU#0]; Stack&-1, GoTo[moTail]; PStore1[LOCAL,RZero]; moLBX: Nop; *Wait for MC1 fault to abort 4th mi. Nop; Skip[IntPending]; Stack _ (Stack) - 1, Return; *MC1 fault aborts this mi. Stack _ (Stack) - 1, LoadPage[opPage0]; T _ 2C, GoTo[NOPint]; *Args are TOS/ cardinal count of words to 0; 2OS,,3OS/ long pointer to block. LongBlkZ: T _ Stack&-1, CallP[StackLPx]; *Setup Long pointer from 2OS,,3OS Stack&+3, Call[.+1]; *Point StkP at count *Loop here to zero all words in the block in reverse order. LU _ Stack; T _ (Stack) - 1, Skip[ALU#0]; Stack&-1, GoTo[moTail]; PStore1[LP,RZero], GoTo[moLBX]; MicVersion: Stack _ (Stack) or (LoA[VersionFlags]); Stack&+1 _ HiA[ReleaseDate]; Stack _ (Stack) or (LoA[ReleaseDate]), GoTo[moTail]; %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. Interesting registers are as follows: 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 *357b NWW Wakeups pending *076b xfWDC Wakeup disable counter *355b prTicks Process tick count *077b xfXTSReg Xfer trap status % ReadR: RTemp _ T, Call[moStkPSave]; GoTo[moRestoreStkPPush]; :ENDIF; ************************************************ :END[MesaX];(1795)\f2