: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
xfMXdest link or indirect link
xfBrkByte40400b + break bytecode to execute
xfXTSRegXfer trap flag
xfFSIframe size index
xfFramepointer to head-of-list for current frame if
freeing it.
xfMYpossible trap parameter
MemStatpossible 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
xfTempglobal frame address
output registers
CODE,CODEhicode base register
GLOBALglobal base register
xfTempmodified 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
Tpointer to frame
xfFSIpointer to head-of-list
temps
xfFrameframe pointer
xBufframe 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
xfTempwhere to save state
+0 to +MaxStack-1stack
+MaxStackStkP
+MaxStack+1LOCAL
temporaries
xfRlinkReturn-to address
xfTemp1set StkP to this depth and pop till empty
xfTemp2StkP 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
xfTempwhere to load state from
MemStatpreserved; FreeFrame bit is checked on exit
output registers
xfMYsource link
xfMXdest link
xfBrkBytebreak instruction replacement
temp registers
xfTemp1count 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 141 = have floating point microcode
Bit 151 = 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
xPageCountCount of ’good’ pages from Initial microcode
345b
xStorageFaultsSum of (2↑bad board no.) from Initial
346b
xHardBadPagesCount of hard bad pages from Initial
347b
xSoftBadPagesCount of soft bad pages from Initial
323b
vCrystalSpeed 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:
64012802560cycles/tick
40 mhz320 160 80
44.5356 178 89
50400 200 100
*357b
NWWWakeups pending
*076b
xfWDCWakeup disable counter
*355b
prTicksProcess tick count
*077b
xfXTSRegXfer trap status
%

ReadR:
RTemp ← T, Call[moStkPSave];
GoTo[moRestoreStkPPush];

:ENDIF; ************************************************

:END[MesaX];