:TITLE[Nova];*Alto/Nova emulator

*Last edited: 28 April 1980 by Fiala

%Naming conventions (not universally followed): Labels are preceded by
one of four prefixes: "ne," "ao," "xo," and "br." Opcode execution begins
on nePage at the mi labeled "ne1st" or on one of several duplicates of
this opcode. Memory reference opcodes use only nePage; A-group opcodes
branch off to aoPage; opcodes in the extended instruction set branch off
to xoPage; BCPL runtime opcodes are divided into three groups: JSR 300-337
are on brJsrPage, JSR @340-357 on br340Page, and JSR @360-377 on nePage.


The mi at location 1 (BufferRefillTrap) is ’LoadPage[0], Goto[377]’,
which sends control to location 377 on the page that did the (aborted)
NextInst/NextData. We would like the mi at 0 to be a PFetch4, but
alas, DF2 addressing doesn’t work, since H2 is not loaded in the cycle
following an aborted mi (so the displacement won’t be loaded).

Buffer refill occurs every four non-jump opcodes and requires 16 cycles
(4 through the PFetch4 + 12 after PFetch4) or 4.0 cycles/opcode; JMP and
JSR independently refill the buffer, and the time for that is attributed
to them. LDA@ and STA@ explicitly check for buffer refill during the dead
time of the indirect fetch, so that IBuf will be loaded by the end of the
opcode; STA also checks for refill prior to its PStore1 because MC1 is busy
for 15 cycles afterwards and buffer refill would be very slow.
%
:IF[neBCPLI340];
xoRefill:
PFetch4[PC,IBuf,4], GotoP[neRefx], At[xoBase,377];
:ENDIF;

neRefill:
PFetch4[PC,IBuf,4], GotoP[.+1], At[neBase,377];

*PC contains a multiple of 4, and the low two bits of the PC are in PCF.
OnPage[0];
neRefx:
PCF ← RZero;
PC ← (PC) + (4C), Return;

*Start Alto/Nova emulator. Initialize bases and constants, then start at PC.
StartNova:
Carry ← 0C;
R177400 ← 177400C, Task;
ROne ← 1C;
RTwo ← 2C;
*
RThree ← 3C;*RThree coincident with rpAC2
rwpAC0 ← IP[AC0]C;
rwpAC1 ← IP[AC1]C;
rwpAC2 ← IP[AC2]C;
rwpAC3 ← IP[AC3]C, Task;
*rpACx contains a pointer to ACx-1 (i.e., (ACx & 360)+((ACx-1) & 17)
*since StkP counts mod 20b.
rpAC0 ← OR[AND[IP[AC0],360],AND[SUB[IP[AC0],1],17]]C;
rpAC1 ← OR[AND[IP[AC1],360],AND[SUB[IP[AC1],1],17]]C;
T ← MDShi, LoadPage[neFixBPage];
rpAC2 ← OR[AND[IP[AC2],360],AND[SUB[IP[AC2],1],17]]C, CallP[FixNBases];
T ← PC, LoadPage[nePage];
rpAC3 ← OR[AND[IP[AC3],360],AND[SUB[IP[AC3],1],17]]C, GotoP[brJmpPz];

OnPage[neFixBPage];
FixNBases:
DMAhi ← T;
PChi ← T;
AC0hi ← T;
AC1hi ← T;
AC2hi ← T;
AC3hi ← T, Return;

%Interrupts are checked for only on opcodes that jump or compute indefinitely
such as BLT/BLKS.

We task (i.e., Return) every 41 cycles by requiring each opcode to Return
within 41 cycles of starting and within 0 cycles of exiting, where JsrFin1+1
or one of its duplicates is the 1st mi.
%
OnPage[nePage];

neMemI:
LU ← (Dispatch[PCF[IBuf],5,4]) or not T, Disp[.+1];

*Timing = 6 cycles to here
*Main Instruction Dispatch for Memory Reference instructions
PCF[IBuf] ← T ← PCF[IBuf] and T, FreezeResult, Disp[JmpJsr], At[OpTab,0];*jmp
PCF[IBuf] ← T ← PCF[IBuf] and T, Disp[JmpJsr], At[OpTab,1];*jsr
T ← PCF[IBuf] and T, Disp[IszDsz], At[OpTab,2];*isz
T ← PCF[IBuf] and T, FreezeResult, Disp[IszDsz], At[OpTab,3];*dsz

*rp’s point to (reg-1) mod 20b because PFetch’s do pushes.
lu ← StkP ← rpAC0, Disp[LdaSta], At[OpTab,4];*lda 0
lu ← StkP ← rpAC1, Disp[LdaSta], At[OpTab,5];*lda 1
lu ← StkP ← rpAC2, Disp[LdaSta], At[OpTab,6];*lda 2
lu ← StkP ← rpAC3, Disp[LdaSta], At[OpTab,7];*lda 3

lu ← (StkP ← rwpAC0) or not T, Disp[LdaSta], At[OpTab,10];*sta 0
lu ← (StkP ← rwpAC1) or not T, Disp[LdaSta], At[OpTab,11];*sta 1
lu ← (StkP ← rwpAC2) or not T, Disp[LdaSta], At[OpTab,12];*sta 2
lu ← (StkP ← rwpAC3) or not T, Disp[LdaSta], At[OpTab,13];*sta 3

LoadPage[xoPage], Disp[Cycle], At[OpTab,14];*60000-63777
T ← PCF[IBuf] or not T, Disp[JSRIIp], At[OpTab,15];*64000-67777
T ← (PCF.word) + 1, Goto[IOUnIm], At[OpTab,16];*70000-73777
T ← (PCF.word) + 1, Goto[IOUnIm], At[OpTab,17];*74000-77777

*Save the current pc + 1 in memory location 527b and jump to location pointed
*to by location 530b + inst[3,7]
IOUnIm:
PC ← (PC) + T;
PCF[IBuf] ← (LdF[PCF[IBuf],3,5]) + 1;
T ← (R400) or (127C), Goto[intXit];

*Dispatch for Jmp/Jsr instructions:
*T contains PCF[IBuf] and 377.

*Timing: JMP = 24, JSR = 33, JMP@ = 38, JSR@ = 40;
*+2 if negative eff. addr; +2 if PC-relative addressing

*Non-indirect Jmp/Jsr
JmpJsr:
PFetch4[MDS,IBuf], DblGoto[JmpFin,JsrFin,Alu<0], At[JmpJsrTab,0];*page 0
:IF[neBCPL300];
LU ← PCF[IBuf] - (300C), DblGoto[brJmpPz,brJsrPz,Alu<0], At[JmpJsrTab,1];*pg 0
:ELSE;
PFetch4[MDS,IBuf], DblGoto[JmpFin,JsrFin,Alu<0], At[JmpJsrTab,1];*pg 0
:ENDIF;
T ← (PCF.word)+T, DblGoto[PCJmp1,PCJsr1,Alu<0], At[JmpJsrTab,2];*pc
T ← (R177400) or T, FreezeResult, Goto[.-1], At[JmpJsrTab,3];*-pc
PFetch4[AC2,IBuf], DblGoto[JmpFin,JsrFin,Alu<0], At[JmpJsrTab,4];*ac2
T ← (R177400) or T, FreezeResult, Goto[.-1], At[JmpJsrTab,5];*-ac2
PFetch4[AC3,IBuf], DblGoto[JmpFin,JsrFin,Alu<0], At[JmpJsrTab,6];*ac3
T ← (R177400) or T, FreezeResult, Goto[.-1], At[JmpJsrTab,7];*-ac3

*Indirect Jmp/Jsr
PFetch1[MDS,RTemp], DblGoto[JmpIndFin,JsrIndFin,Alu<0], At[JmpJsrTab,10]; *@pg 0
:IF[neBCPLI340];
LU ← PCF[IBuf] - (340C), DblGoto[JmpPzInd,JsrPzInd,Alu<0], At[JmpJsrTab,11]; *@pg 0
:ELSEIF[neBCPLI360];
LU ← PCF[IBuf] - (360C), DblGoto[JmpPzInd,JsrPzInd,Alu<0], At[JmpJsrTab,11]; *@pg 0
:ELSE;
PFetch1[MDS,RTemp], DblGoto[JmpIndFin,JsrIndFin,Alu<0], At[JmpJsrTab,11]; *@pg 0
:ENDIF;
T ← PCF[RZero] + T, FreezeResult, Goto[PCIndJmpJsr], At[JmpJsrTab,12]; *pc
T ← (R177400) or T, FreezeResult, Goto[.-1], At[JmpJsrTab,13]; *-pc
PFetch1[AC2,RTemp], DblGoto[JmpIndFin,JsrIndFin,Alu<0], At[JmpJsrTab,14]; *ac2
T ← (R177400) or T, FreezeResult, Goto[.-1], At[JmpJsrTab,15]; *-ac2
PFetch1[AC3,RTemp], DblGoto[JmpIndFin,JsrIndFin,Alu<0], At[JmpJsrTab,16]; *ac3
T ← (R177400) or T, FreezeResult, Goto[.-1], At[JmpJsrTab,17]; *-ac3

PCtoAC3:
T ← (PCF.word)+T+1;
AC3 ← T, Return;

*Entry from EIR, brBranch
PCJmp1:
PFetch4[PC,IBuf], Goto[JmpFin];*Odd

PCJsr1:
PFetch4[PC,IBuf];*Even
JsrFin:
MNBR ← PC, PC ← T ← T, NoRegILockOK;*Even; bypass kludge
T ← MNBR, Call[PCtoAC3];*PC←new PC*2, AC3←old PC+1
T ← PC;
PC ← (PC) + T, Goto[JsrFin1];

PCIndJmpJsr:
PFetch1[PC,RTemp], DblGoto[JmpIndFin,JsrIndFin,Alu<0];

JsrIndFin:
T ← PC, Call[PCtoAC3];*Even; entry from JSRII/JSRIS
JmpIndFin:
T ← RTemp;*Odd
*Entry from StartNova, brReturn, brBranch
brJmpPz:
PFetch4[MDS,IBuf];
*Entry here on BitBlt interrupt or exit, LRJ continue.
JmpFin:
T ← PC ← T, Task, At[JmpFinLoc];*Odd; bypass kludge
PC ← (PC) + T;
JsrFin1:
LU ← NWW, LoadPage[neIntPage0], Call[JmpFin3];

*Return here to start next inst with PCF pointing at odd byte.
*Many opcodes finish by returning (which accomplishes the tasking requirement)

ne1st:
CSkipData, T ← AllOnes;*T ← 377

ne2nd:
Dispatch[PCF[IBuf],1,4], DblGoto[neRegI,neMemI,R<0];

neRet:
Return;

JmpPzInd:
PFetch1[MDS,RTemp], Goto[JmpIndFin];
JsrPzIF:
PFetch1[MDS,RTemp], Goto[JsrIndFin];

JmpFin3:
PCF ← PC, PC ← T, NoRegILockOK, SkipP[Alu#0];*Skip if possible int
OnPage[neIntPage0];
PC ← (PC) and not (3C), Return;
LU ← NWW, Skip[R>=0];*Skip if interrupts enabled
*BlksLp enters here with LU ← NWW, DblGoto[intDis,intEna,R<0];
intDis:
PC ← (PC) and not (3C), Return;
intEna:
PC ← (PC) and not (3C), Skip[Alu#0];*Skip if int requests
*BLT/BLKS enter interrupts with DblGoto[intEnt,int0Ret,Alu#0]
int0Ret: Return;
*Begin an interrupt unless the interrupting device is inactive.
*Worst case timing from here to Return is 27 cycles.
intEnt:
T ← (R400) + (52C);
PFetch2[MDS,WW];*Odd; fetch WW and ACTIVE
DMA ← T, LoadPage[neIntPage1];
T ← NWW, GotoP[.+1];
OnPage[neIntPage1];
WW ← T ← (WW) or T;
ACTIVE ← T ← (ACTIVE) and T;*ACTIVE now holds active int req’s
NWW ← T ← (Zero) - T, Skip[Alu#0];
intPS2:
PStore1[DMA,WW,0], Return;*Return with NWW .eq. 0
*Start an interrupt
T ← (ACTIVE) and T, Task;*Odd; ACTIVE & -ACTIVE = right-most 1
WW ← (WW) and not T;
PCF[IBuf] ← 1C, Call[intPS2];*RTemp1 will contain interrupt level
NWW ← 100000C, Call[intT8];*Disable interrupts

*loop to get number of the highest priority interrupt
intT8:
ACTIVE ← Rsh[ACTIVE,1], Goto[intT9,R odd];
PCF[IBuf] ← PCF[IBuf] + 1, Return;

*enter int routine - save other interrupts in WW (452)
intT9:
T ← PCF.word;*recover the PC
PC ← (PC) or T, LoadPage[nePage];
T ← (R400) or (100C), GotoP[.+1];
OnPage[nePage];
*Also enter here from IOUnIm
intXit:
PStore1[MDS,PC], Call[neRet];*save PC at 500b
T ← PCF[IBuf] + T, Goto[JmpPzInd];*T ← address of new PC

*Dispatch for Isz/Dsz instructions:
*These opcodes are executed so rarely that speed is of little importance.
*T contains PCF[IBuf] and 377

*Non-indirect Isz/Dsz
IszDsz:
PFetch1[MDS,RTemp], DblGoto[Dsz1,Isz1,Alu<0], At[IszDszTab,0];*pg 0
PFetch1[MDS,RTemp], DblGoto[Dsz1,Isz1,Alu<0], At[IszDszTab,1];*pg 0
T ← PCF[RZero] + T, FreezeResult, Goto[PCDszIsz], At[IszDszTab,2]; *pc
T ← (R177400) or T, FreezeResult, Goto[.-1], At[IszDszTab,3];*-pc
PFetch1[AC2,RTemp], DblGoto[Dsz1,Isz1,Alu<0], At[IszDszTab,4];*ac2
T ← (R177400) or T, FreezeResult, Goto[.-1], At[IszDszTab,5];*-ac2
PFetch1[AC3,RTemp], DblGoto[Dsz1,Isz1,Alu<0], At[IszDszTab,6];*ac3
T ← (R177400) or T, FreezeResult, Goto[.-1], At[IszDszTab,7];*-ac3

*Indirect Isz/Dsz
PFetch1[MDS,RTemp], FreezeResult, Goto[IndDszIsz], At[IszDszTab,10];
PFetch1[MDS,RTemp], FreezeResult, Goto[IndDszIsz], At[IszDszTab,11];
T ← PCF[RZero] + T, FreezeResult, Goto[PCIndDszIsz], At[IszDszTab,12];
T ← (R177400) or T, FreezeResult, Goto[.-1], At[IszDszTab,13];
PFetch1[AC2,RTemp], FreezeResult, Goto[IndDszIsz], At[IszDszTab,14];
T ← (R177400) or T, FreezeResult, Goto[.-1], At[IszDszTab,15];
PFetch1[AC3,RTemp], FreezeResult, Goto[IndDszIsz], At[IszDszTab,16];
T ← (R177400) or T, FreezeResult, Goto[.-1], At[IszDszTab,17];

PCDszIsz:
PFetch1[PC,RTemp], DblGoto[Dsz1,Isz1,Alu<0];

Isz1:
T ← T, Task;*Even; save efadr with bypass kludge
RTemp ← (RTemp) + (2C);
Dsz1:
T ← T, CSkipData, Call[neRet];*Odd; save efadr with bypass kludge
RTemp ← (RTemp) - 1;
PStore1[MDS,RTemp], DblGoto[neTask1st,neTaskSkp,Alu#0];

PCIndDszIsz:
PFetch1[PC,RTemp], FreezeResult;
IndDszIsz:
T ← RTemp, FreezeResult, Goto[IszDsz];

neTaskSkp:
SkipData, Call[.+1];*Even; may cause refill (fake call)
neCS1st:
CSkipData, Call[neRet];*Skip even byte of opcode (no refill)
CSkipData, T ← AllOnes, Goto[ne2nd];

*Opcodes that compute for too long to return to JmpFin+2 exit at
*neTask1st to task immediately before starting the next opcode.
neTask1st:
Call[neRet];*Odd
CSkipData, T ← AllOnes, Goto[ne2nd];

*Average timing: LDA = 17, STA = 19.25, LDA@ = 30.25, STA@ = 30.75;
*+ 2 if PC-relative

*In addition, an A-group opcode referencing the AC of an immediately preceding
*LDA/LDA@ will be slowed by 2 cycles; a LDA, LDA@, or STA@ following a
*STA/STA@ will be slowed by 4 cycles (but slowed by 0 after buffer refill or
*by only 2 if PC-relative); a JSR, JMP, JSR@, or JMP@ will be slowed by
*4 (positive efadr) or 6 (negative efadr) cycles (but by only 0 or 2 cycles
*if buffer refill occurred).

**Maximum time to Return = 32 cycles on PC-rel STA@ barring error-correction.

*Non-indirect Lda/Sta (CNextData’s obtain odd byte of opcode = efadr)
LdaSta:
T ← CNextData[IBuf], DblGoto[PzSta,PzLda,Alu<0], At[LdaStaTab,0]; *pg 0
T ← CNextData[IBuf], DblGoto[PzSta,PzLda,Alu<0], At[LdaStaTab,1]; *pg 0
T ← PCF[RZero], FreezeResult, Goto[PCLdaSta], At[LdaStaTab,2]; *pc
T ← PCF[RZero] or not T, FreezeResult, Goto[PCLdaSta], At[LdaStaTab,3]; *-pc
T ← CNextData[IBuf], DblGoto[AC2Sta,AC2Lda,Alu<0], At[LdaStaTab,4]; *ac2
T ← CNextData[IBuf] or not T, DblGoto[AC2Sta,AC2Lda,Alu<0], At[LdaStaTab,5]; *-ac2
T ← CNextData[IBuf], DblGoto[AC3Sta,AC3Lda,Alu<0], At[LdaStaTab,6]; *ac3
T ← CNextData[IBuf] or not T, DblGoto[AC3Sta,AC3Lda,Alu<0], At[LdaStaTab,7]; *-ac3

*Indirect Lda/Sta
T ← CNextData[IBuf], FreezeResult, Goto[PzLdaStaInd], At[LdaStaTab,10]; *@pg 0
T ← CNextData[IBuf], FreezeResult, Goto[PzLdaStaInd], At[LdaStaTab,11]; *@pg 0
T ← PCF[RZero], FreezeResult, Goto[PCLdaStaInd], At[LdaStaTab,12]; *@pc
T ← PCF[RZero] or not T, FreezeResult, Goto[PCLdaStaInd], At[LdaStaTab,13]; *@-pc
T ← CNextData[IBuf], FreezeResult, Goto[AC2LdaStaInd], At[LdaStaTab,14]; *@ac2
T ← CNextData[IBuf] or not T, FreezeResult, Goto[AC2LdaStaInd], At[LdaStaTab,15]; *@-ac2
T ← CNextData[IBuf], FreezeResult, Goto[AC3LdaStaInd], At[LdaStaTab,16]; *@ac3
T ← CNextData[IBuf] or not T, FreezeResult, Goto[AC3LdaStaInd], At[LdaStaTab,17]; *@-ac3

*The check for buffer refill costs 2 cycles 3/4 of the time, when refill
*doesn’t occur but saves 14 cycles 1/4 of the time when refill occurs,
*for an average saving of 2 cycles/STA.
StaIFF:
PFetch4[PC,IBuf,4];
PCF ← RZero;
PC ← (PC) + (4C);
PzStaF:
PStore1[MDS,Stack], Return;

PCSta:
T ← (PC) + T, DblGoto[StaIFF,PzStaF,BPCChk];*Odd
AC2Sta:
T ← (AC2) + T, DblGoto[StaIFF,PzStaF,BPCChk];*Odd
AC3Sta:
T ← (AC3) + T, DblGoto[StaIFF,PzStaF,BPCChk];*Odd
PzSta:
DblGoto[StaIFF,PzStaF,BPCChk];*Odd

PCLdaSta:
T ← CNextData[IBuf] + T, DblGoto[PCSta,PCLda,Alu<0];

*Refill check saves 3.5 cycles/LDA@
LdaIndFin:
Goto[LdaIndF1,BPCChk’];*Even
PFetch4[PC,IBuf,4];*Odd
PCF ← RZero;
PC ← (PC) + (4C);
LdaIndF1:
T ← RTemp;*Even
PzLda:
PFetch1[MDS,Stack], Return;*Even
PCLda:
PFetch1[PC,Stack], Return;*Even
AC2Lda:
PFetch1[AC2,Stack], Return;*Even
AC3Lda:
PFetch1[AC3,Stack], Return;*Even

*Refill check saves 5.75 cycles/STA@.
StaIndFin:
Goto[StaIndF1,BPCChk’];*Odd
PFetch4[PC,IBuf,4];*Odd
PCF ← RZero;
PC ← (PC) + (4C);
StaIndF1:
T ← RTemp, Goto[PzStaF];*Even

PCLdaStaInd:
T ← CNextData[IBuf] + T, FreezeResult;
PFetch1[PC,RTemp], DblGoto[StaIndFin,LdaIndFin,Alu<0];
PzLdaStaInd:
PFetch1[MDS,RTemp], DblGoto[StaIndFin,LdaIndFin,Alu<0];
AC2LdaStaInd:
PFetch1[AC2,RTemp], DblGoto[StaIndFin,LdaIndFin,Alu<0];
AC3LdaStaInd:
PFetch1[AC3,RTemp], DblGoto[StaIndFin,LdaIndFin,Alu<0];

*Dispatch table for register-register instructions. 16-way Dispatch on
*SrcAc,,DestAc is pending.

*Average timing: 28 to 32 cycles on logical; 30 to 38 cycles on arithmetic.
*Opcodes that skip require an additional 7.25 cycles.

**Max time to Return is 41 cycles on opcodes that skip and refill buffer.

neRegI:
PCF[IBuf] ← Rcy[PCF[IBuf],3], Disp[.+1];
StkP ← rwpAC0, Goto[neSrc0], At[RegOpTab,0];*SrcAC = 0, DestAC = 0
StkP ← rwpAC1, Goto[neSrc0], At[RegOpTab,1];*SrcAC = 0, DestAC = 1
StkP ← rwpAC2, Goto[neSrc0], At[RegOpTab,2];*SrcAC = 0, DestAC = 2
StkP ← rwpAC3, Goto[neSrc0], At[RegOpTab,3];*SrcAC = 0, DestAC = 3
StkP ← rwpAC0, Goto[neSrc1], At[RegOpTab,4];*SrcAC = 1, DestAC = 0
StkP ← rwpAC1, Goto[neSrc1], At[RegOpTab,5];*SrcAC = 1, DestAC = 1
StkP ← rwpAC2, Goto[neSrc1], At[RegOpTab,6];*SrcAC = 1, DestAC = 2
StkP ← rwpAC3, Goto[neSrc1], At[RegOpTab,7];*SrcAC = 1, DestAC = 3
StkP ← rwpAC0, Goto[neSrc2], At[RegOpTab,10];*SrcAC = 2, DestAC = 0
StkP ← rwpAC1, Goto[neSrc2], At[RegOpTab,11];*SrcAC = 2, DestAC = 1
StkP ← rwpAC2, Goto[neSrc2], At[RegOpTab,12];*SrcAC = 2, DestAC = 2
StkP ← rwpAC3, Goto[neSrc2], At[RegOpTab,13];*SrcAC = 2, DestAC = 3
StkP ← rwpAC0, Goto[neSrc3], At[RegOpTab,14];*SrcAC = 3, DestAC = 0
StkP ← rwpAC1, Goto[neSrc3], At[RegOpTab,15];*SrcAC = 3, DestAC = 1
StkP ← rwpAC2, Goto[neSrc3], At[RegOpTab,16];*SrcAC = 3, DestAC = 2
StkP ← rwpAC3, Goto[neSrc3], At[RegOpTab,17];*SrcAC = 3, DestAC = 3

neSrc0:
T ← AC0, LoadPage[aoPage], Goto[neFnD];
neSrc1:
T ← AC1, LoadPage[aoPage], Goto[neFnD];
neSrc2:
T ← AC2, LoadPage[aoPage], Goto[neFnD];
neSrc3:
T ← AC3, LoadPage[aoPage], Goto[neFnD];

:IF[neFastAGroup];
neFnD:
Dispatch[PCF[IBuf],10,3], GotoP[.+1];*Function field
OnPage[aoPage];
Dispatch[PCF[IBuf],13,4], Disp[aoFNC];*Shift and carry fields

%Put the function result in both T and the smashable temporary below the
destination AC. Disp into either aoSHC (logical) or aoSHCc (arithmetic);
arithmetic operations complement the incoming carry if the ALU carry-out
is 1.
%
aoFNC:
T ← Stack&-1 ← (Zero) xnor T, Disp[aoSHC],At[aoFunc,0];*com
T ← Stack&-1 ← (Zero) - T, Disp[aoSHCc],At[aoFunc,1];*neg
Stack&-1 ← T, Disp[aoSHC],At[aoFunc,2];*mov
T ← Stack&-1 ← (Zero) + T +1, Disp[aoSHCc],At[aoFunc,3];*inc
T ← Stack&-1 ← (Stack&-1) - T -1, Disp[aoSHCc],At[aoFunc,4];*adc
T ← Stack&-1 ← (Stack&-1) - T, Disp[aoSHCc],At[aoFunc,5];*sub
T ← Stack&-1 ← (Stack&-1) + T, Disp[aoSHCc],At[aoFunc,6];*add
T ← Stack&-1 ← (Stack&-1) and T, Disp[aoSHC],At[aoFunc,7];*and

*We use Carry = 177777 for carry-in = 1, Carry = 0 for carry-in = 0
aoSHC:
LU ← Carry, DblGoto[aoNN,aoNZ,Alu#0], At[aoSH0,0];*Nosh, Carry
DblGoto[cZrN,cZrZ,Alu#0], At[aoSH0,1];*Nosh, 0
DblGoto[cNrN,cNrZ,Alu#0], At[aoSH0,2];*Nosh, 1
LU ← (Carry) xnor (0C), DblGoto[aoNN,aoNZ,Alu#0], At[aoSH0,3];*Nosh, Carry’
Carry, DblGoto[aoL1,aoL0,R<0], At[aoSH0,4];*Lsh, Carry
T ← Lsh[Stack,1], DblGoto[aoFC1,aoFC0,R<0], At[aoSH0,5];*Lsh, 0
T ← (Lsh[Stack,1])+1, DblGoto[cNrNa,cZrNa,R<0], At[aoSH0,6];*Lsh, 1
Carry, DblGoto[aoL1a,aoL0a,R>=0], At[aoSH0,7];*Lsh, Carry’
Carry, T ← 100000C, DblGoto[aoR1,aoR0,R<0], At[aoSH0,10];*Rsh, Carry
T ← Rsh[Stack,1], DblGoto[aoFC1,aoFC0,R Odd], At[aoSH0,11];*Rsh, 0
T ← Stack ← Rcy[Stack,1], DblGoto[aoRO,aoRE,R Odd], At[aoSH0,12];*Rsh, 1
Carry, T ← 100000C, DblGoto[aoR1a,aoR0a,R>=0], At[aoSH0,13];*Rsh, Carry’
LU ← Carry, DblGoto[aoSN,aoSZ,Alu#0], At[aoSH0,14];*Swap, Carry
T ← Rcy[Stack,10], DblGoto[cZrN,cZrZ,Alu#0], At[aoSH0,15];*Swap, 0
T ← Rcy[Stack,10], DblGoto[cNrN,cNrZ,Alu#0], At[aoSH0,16];*Swap, 1
LU ← (Carry) xnor (0C), DblGoto[aoSN,aoSZ,Alu#0], At[aoSH0,17];*Swap, Carry’

*Arithmetic ALU operations use this table.
*The Rsh-Carry’ and Swap-Carry’ table entries are never executed by the
*Executive, Bravo, or FTP.
aoSHCc:
LU ← (Carry)+1, UseCOutAsCIn, DblGoto[aoNN,aoNZ,Alu#0], At[aoSH1,0];*Nosh, Carry
LU ← (RZero)+1, UseCOutAsCIn, DblGoto[aoNN,aoNZ,Alu#0], At[aoSH1,1];*Nosh, 0
LU ← (AllOnes)+1, UseCOutAsCIn, DblGoto[aoNN,aoNZ,Alu#0], At[aoSH1,2];*Nosh, 1
T ← Carry, FreezeResult, Goto[aoNX], At[aoSH1,3];*Nosh, Carry’
T ← (Carry)+1, UseCOutAsCIn, DblGoto[aoLS,aoLA,R<0], At[aoSH1,4];*Lsh, Carry
T ← (Stack)+T, UseCOutAsCIn, DblGoto[aoFC1,aoFC0,R<0], At[aoSH1,5];*Lsh, 0
T ← (AllOnes)+1, UseCOutAsCIn, Goto[aoLS], At[aoSH1,6];*Lsh, 1
LU ← (Carry)+1, UseCOutAsCIn, Goto[aocL], At[aoSH1,7];*Lsh, Carry’
LU ← (Carry)+1, UseCOutAsCIn, Goto[aocR], At[aoSH1,10];*Rsh, Carry
T ← 100000C, DblGoto[aoR1,aoR0,Carry], At[aoSH1,11];*Rsh, 0
T ← 100000C, DblGoto[aoR1a,aoR0a,Carry’], At[aoSH1,12];*Rsh, 1
LU ← (Carry)+1, UseCOutAsCIn, Goto[aocRa], At[aoSH1,13];*Rsh, Carry’
LU ← (Carry)+1, UseCOutAsCIn, DblGoto[aoSN,aoSZ,Alu#0], At[aoSH1,14];*Swap, Carry
LU ← (RZero)+1, UseCOutAsCIn, DblGoto[aoSN,aoSZ,Alu#0], At[aoSH1,15];*Swap, 0
LU ← (AllOnes)+1, UseCOutAsCIn, DblGoto[aoSN,aoSZ,Alu#0], At[aoSH1,16];*Swap, 1
T ← Carry, FreezeResult, Goto[aoSX], At[aoSH1,17];*Swap, Carry’

aoNN:
T ← Stack, DblGoto[cNrNa,cZrNa,Alu#0];*Odd
aoNZ:
T ← Stack, DblGoto[cNrZa,cZrZa,Alu#0];*Even

aoSN:
T ← Rcy[Stack,10], DblGoto[cNrNa,cZrNa,Alu#0];*Odd
aoSZ:
T ← Rcy[Stack,10], DblGoto[cNrZa,cZrZa,Alu#0];*Even

aoL1:
T ← (Lsh[Stack,1])+1, DblGoto[cNrNa,cZrNa,R<0];
aoL0:
T ← Lsh[Stack,1], DblGoto[aoFC1,aoFC0,R<0];

aoL1a:
T ← (Lsh[Stack,1])+1, DblGoto[cNrNa,cZrNa,R<0];
aoL0a:
T ← Lsh[Stack,1], DblGoto[aoFC1,aoFC0,R<0];

aoFC1:
DblGoto[cNrN,cNrZ,Alu#0];*Odd
aoFC0:
DblGoto[cZrN,cZrZ,Alu#0];*Even

aoRO:
Dispatch[PCF[IBuf],2,1], DblGoto[cNrNLd,cNrLd,R Odd];
aoRE:
T ← (Stack) or (100000C), Goto[cZrN];

aoR1:
T ← (Rsh[Stack,1]) or T, DblGoto[cNrNa,cZrNa,R Odd];
aoR0:
T ← Rsh[Stack,1], DblGoto[aoFC1,aoFC0,R Odd];

aoR1a:
T ← (Rsh[Stack,1]) or T, DblGoto[cNrNa,cZrNa,R Odd];
aoR0a:
T ← Rsh[Stack,1], DblGoto[aoFC1,aoFC0,R Odd];

aoNX:
LU ← (RZero)-T-1, UseCOutAsCIn, DblGoto[aoNN,aoNZ,Alu#0];

aoLS:
T ← (Lsh[Stack,1]) - T, DblGoto[aoFC1,aoFC0,R<0];
aoLA:
T ← (Lsh[Stack,1]) + T, DblGoto[aoFC1,aoFC0,R<0];

aocL:
DblGoto[aoL1a,aoL0a,Alu=0];

aocR:
T ← 100000C, DblGoto[aoR1,aoR0,Alu#0];

aocRa:
T ← 100000C, DblGoto[aoR1a,aoR0a,Alu=0];

aoSX:
LU ← (RZero)-T-1, UseCOutAsCIn, DblGoto[aoSN,aoSZ,Alu#0];

cNrZa:
Dispatch[PCF[IBuf],0,3], DblGoto[cNrNLd,cNrLd,R Odd];
cZrZa:
Dispatch[PCF[IBuf],0,3], DblGoto[cZrNLd,cZrLd,R Odd];
:ELSE;
neFnD:
Dispatch[PCF[IBuf],15,2], GotoP[.+1];*Carry field
OnPage[aoPage];
Dispatch[PCF[IBuf],10,3], Disp[aoCRY];*Function field

aoCRY:
LU ← Carry, Disp[aoFNC], At[aoCY0,0];*cin ← Carry
LU ← 0C, Disp[aoFNC], At[aoCY0,1];*cin ← 0
LU ← 100000C, Disp[aoFNC], At[aoCY0,2];*cin ← 1
LU ← (Carry) xnor (0C), Disp[aoFNC], At[aoCY0,3];*cin ← Carry’

%Put the function result in both T and the smashable temporary below the
destination AC. Disp into either neSHC (logical) or neSHCc (arithmetic);
arithmetic operations complement the incoming carry if the ALU carry-out
is 1.
%
aoFNC:
T ← Stack&-1 ← (Zero) xnor T, DblGoto[aoNTC1,aoNTC0,Alu<0], At[aoFunc,0];*com
T ← Stack&-1 ← (Zero) - T, DblGoto[aoTC1,aoTC0,Alu<0], At[aoFunc,1];*neg
Stack&-1 ← T, DblGoto[aoNTC1,aoNTC0,Alu<0], At[aoFunc,2];*mov
T ← Stack&-1 ← (Zero) + T +1, DblGoto[aoTC1,aoTC0,Alu<0], At[aoFunc,3];*inc
T ← Stack&-1 ← (Stack&-1) - T -1, DblGoto[aoTC1,aoTC0,Alu<0], At[aoFunc,4];*adc
T ← Stack&-1 ← (Stack&-1) - T, DblGoto[aoTC1,aoTC0,Alu<0], At[aoFunc,5];*sub
T ← Stack&-1 ← (Stack&-1) + T, DblGoto[aoTC1,aoTC0,Alu<0], At[aoFunc,6];*add
T ← Stack&-1 ← (Stack&-1) and T, DblGoto[aoNTC1,aoNTC0,Alu<0], At[aoFunc,7];*and

*Alu carry out has no effect on carryin--dispatch on shift field
aoNTC0:
Dispatch[PCF[IBuf],13,2], Goto[aoCo0];
aoNTC1:
Dispatch[PCF[IBuf],13,2], Goto[aoCo1];

*Alu carry complements carryin--dispatch on shift field
aoTC0:
Dispatch[PCF[IBuf],13,2], DblGoto[aoCo1,aoCo0,Carry];*carryin = 0
aoTC1:
Dispatch[PCF[IBuf],13,2], DblGoto[aoCo0x,aoCo1x,Carry];*carryin = 1

aoCo0:
LU ← Stack, Disp[aoSH00];
aoCo1:
LU ← Stack, Disp[aoSH10];

aoCo0x:
LU ← Stack, Disp[aoSH00];
aoCo1x:
LU ← Stack, Disp[aoSH10];

*Shift dispatch for final carry = 0
aoSH00:
DblGoto[cZrZ,cZrN,Alu=0], At[aoSH0,0];
T ← Stack ← Lsh[Stack,1], DblGoto[aoFC1,aoFC0,R<0], At[aoSH0,1];
T ← Stack ← Rsh[Stack,1], DblGoto[aoFC1,aoFC0,R Odd], At[aoSH0,2];
T ← Stack ← Lcy[Stack,10], DblGoto[cZrZ,cZrN,Alu=0], At[aoSH0,3];

aoSH10:
DblGoto[cNrZ,cNrN,Alu=0], At[aoSH1,0];
T ← Stack ← (Lsh[Stack,1]) + 1, DblGoto[cNrNa,cZrNa,R<0], At[aoSH1,1];
T ← Stack ← Rcy[Stack,1], DblGoto[aoF1r1,aoF0r1,R Odd], At[aoSH1,2];
T ← Stack ← Lcy[Stack,10], DblGoto[cNrZ,cNrN,Alu=0], At[aoSH1,3];

aoFC0:
DblGoto[cZrZ,cZrN,Alu=0];
aoFC1:
DblGoto[cNrZ,cNrN,Alu=0];

aoF0r1:
T ← (Stack) or (100000C), Goto[cZrN];
aoF1r1:
Dispatch[PCF[IBuf],2,1], DblGoto[cNrNLd,cNrLd,R Odd];
:ENDIF;

cZrNa:
Dispatch[PCF[IBuf],1,2], DblGoto[cZrNLd,cZrLd,R Odd];
cNrNa:
Dispatch[PCF[IBuf],2,1], DblGoto[cNrNLd,cNrLd,R Odd];

cZrZ:
Dispatch[PCF[IBuf],0,3], DblGoto[cZrNLd,cZrLd,R Odd];
cZrN:
Dispatch[PCF[IBuf],1,2], DblGoto[cZrNLd,cZrLd,R Odd];

cNrZ:
Dispatch[PCF[IBuf],0,3], DblGoto[cNrNLd,cNrLd,R Odd];
cNrN:
Dispatch[PCF[IBuf],2,1], DblGoto[cNrNLd,cNrLd,R Odd];*Either table ok

cZrNLd:
Stack&-1, Disp[.+2];*No load
cZrLd:
Carry ← 0C, Disp[.+1];*Load
Stack&+1 ← T, CSkipData, Return, At[aoXitT0,0];*--
Stack&+1 ← T, CSkipData, Goto[aoSkip], At[aoXitT0,1];*Skp
Stack&+1 ← T, CSkipData, Goto[aoSkip], At[aoXitT0,2];*szc
Stack&+1 ← T, CSkipData, Return, At[aoXitT0,3];*snc
Stack&+1 ← T, CSkipData, Goto[aoSkip], At[aoXitT0,4];*szr
Stack&+1 ← T, CSkipData, Return, At[aoXitT0,5];*snr
Stack&+1 ← T, CSkipData, Goto[aoSkip], At[aoXitT0,6];*sez
Stack&+1 ← T, CSkipData, Return, At[aoXitT0,7];*sbn

cNrNLd:
Stack&-1, Disp[.+2];*No load
cNrLd:
Carry ← (Carry) or not (0C), Disp[.+1];*Load
Stack&+1 ← T, CSkipData, Return, At[aoXitT1,0];
Stack&+1 ← T, CSkipData, Goto[aoSkip], At[aoXitT1,1];
Stack&+1 ← T, CSkipData, Return, At[aoXitT1,2];
Stack&+1 ← T, CSkipData, Goto[aoSkip], At[aoXitT1,3];
Stack&+1 ← T, CSkipData, Goto[aoSkip], At[aoXitT1,4];
Stack&+1 ← T, CSkipData, Return, At[aoXitT1,5];
Stack&+1 ← T, CSkipData, Goto[aoSkip], At[aoXitT1,6];
Stack&+1 ← T, CSkipData, Return, At[aoXitT1,7];

%Doing refill this way rather averages .25 cycles/opcode faster than with:
CSkipData, Task;
CSkipData;
T ← AllOnes, CSkipData, Goto[ne2nd];
and allows the A-group mi to be on a different page from ne2nd and the memory
reference mi; also worst case time to Return is 9 cycles compared to 10
cycles for the trap. Skips would average 2 cycles/opcode faster if the
CSkipData in the exit table could be moved earlier, so that the DblGoto at
aoSkip could be incorporated in the exit mi.
%
aoSkip:
Skip[BPCChk];
CSkipData, Goto[WRTRAM];*Cannot cause refill
PFetch4[PC,IBuf,4];*Refill buffer and skip
PCF ← RTwo;
PC ← (PC) + (4C), Return;

*Alto augmented instruction set

*60000
CYCLELeft Rotate

*61000
DIRDisable interrupts
*61001
EIREnable interrupts
*61002
BRIBranch and Return from interrupt
*61003
RCLKRead Clock
*61004
SIOStart I/O
*61005
BLTBlock Transfer
*61006
BLKSBlock Store
*61007
**SITStart Interval Timer - Returns -1
*61010
JMPRAMJump to RAM - only works if AC1 = 420 (enters Mesa)
*61011
RDRAMRead RAM - Returns -1
*61012
WRTRAMWrite RAM - NOP
*61013
DIRSDisable interrupts and skip if on
*61014
VERSVersion - AC0 ← 40000C
*61015
**DREADDouble-word read (altoII only)
*61016
**DWRITEDouble-word write (altoII only)
*61017
**DEXCHDouble-word exchange (altoII only)
*61020
MULUnsigned Multiply
*61021
DIVUnsigned Divide
*61022
WMDS(IME instruction replacing AltoII DIAGNOSE1)
*61023
**DIAGNOSE2Diagnostic (altoII only)
*61024
BITBLTBit Block Transfer
*61036
LOADRAMimplementation pending
*61037
SDPSetDefaultPartition

*64400
JSRIIJump to subroutine, double indirect, pc relative
*65000
JSRISJump to subroutine, double indirect, ac2 relative
*67000
CONVERTScan conversion of characters

*NOTE: instructions with ** are not implemented, and will bomb out if executed


*Opcode 60000 - Cycle
*Left cycle AC0 by inst[12-15d], or by AC1 if count is 0.
Cycle:
PCF[IBuf] and (17C), GotoP[.+1], At[IO0Tab,0];*Test cycle count = 0

OnPage[xoPage];
PCF[IBuf] ← Lsh[PCF[IBuf],4], Goto[.+3,Alu#0];
T ← Lsh[AC1,4];*cycle by AC1 if count=0
PCF[IBuf] ← T;
PCF[IBuf] ← (PCF[IBuf]) or (17C);
CycleControl ← CNextData[IBuf];*DBX←cycle count, MWX←17b
AC0 ← RF[AC0], Return;*Return to next opcode

*Opcodes 61000 - 61377
xoDisp:
Dispatch[PCF[IBuf],13,4], DblGotoP[NoParA,NoParB,R Even], At[IO0Tab,4];

OnPage[xoPage];

*StkP must point at AC1 for BitBlt
NoParA:
StkP ← rwpAC1, Disp[DIR];*Timing 12 thru here
NoParB:
StkP ← rwpAC1, Disp[EIR];*Timing 13 thru here

*JSRII - 64400, 64600
*JSR double indirect, PC relative
JSRIIp:
T ← PCF[IBuf] and (377C), At[IO1Tab,2]; *EfAddr positive
JSRIIn:
T ← (PCF.word) + T, At[IO1Tab,3]; *EfAddr negative
PFetch1[PC,RTemp], Call[neRet];
JSRIS:
T ← RTemp, Goto[JsrPzIF];

*JSRIS - 65000, 65200
*JSR double indirect, AC2 relative
JSRISp:
T ← PCF[IBuf] and (377C), At[IO1Tab,4]; *EfAddr positive
JSRISn:
PFetch1[AC2,RTemp], Goto[JSRIS], At[IO1Tab,5]; *EfAddr negative

%CONVERT - Opcode 67000, 67200
Registers:
ac0:destination word address minus NWRDS
ac2+ Disp points to two word block:
word 0NWRDS -- number of words per scanline (< 400c)
word 1dba -- minus dest bit addr mod 20c
ac3:pointer to word xh of the character descriptor block

Character Descriptor Block:
words 0:xh-1bit map for character
word xh:xw -- (2*width) + 1, or (2*pseudochar)if extension required
word xh+1:hd,,xh -- (scan lines to skip),,(height of bit map)
%
Convertp:
T ← PCF[IBuf] and (377C), At[IO1Tab,14];
Convertn:
PFetch1[AC2,RTemp1], At[IO1Tab,15];*fetch NWRDS
T ← (RZero) + T + 1, LoadPage[ConvertPage1];
PFetch1[MDS,AC1], GotoP[.+1];
OnPage[ConvertPage1];
PFetch1[AC3,RTemp,0];*RTemp←self-relative ptr to xw
T ← AC0, Task;
DMA ← T, CSkipData;*setup for later, advance PC
T ← (RTemp) - 1;*self-relative ptr to xw - 1
AC3 ← (AC3) + T, Task;*point AC3 to start of the block
RTemp ← 16C;
PFetch1[AC3,xnXH,2];*fetch hd,,xh
AC1 ← T ← (AC1) and (17C);*mask dba
RTemp ← (RTemp) - T, Call[.+3];*DMA ← DMA + (hd*xnNWRDS)
*Point DMA to the first dest word
xnXH ← (xnXH) + (177400C);
DMA ← (DMA) + T, Skip[ALU<0];
cvRT1toT: T ← RTemp1, Return;

xnXH ← T ← (LDF[xnXH,10,10]) - 1;*also decrement xh
T ← (AC3) - T, LoadPage[ConvertPage2];
SMA ← T, GotoP[.+1];
OnPage[ConvertPage2];
xnCVLOOP:
PFetch1[MDS,AC3], Task; *fetch source
XBI ← pXBuf;
xnXH ← (xnXH) - 1, Goto[xnCNVEND,R<0];*test count
PFetch4[DMA,xBuf,0];*fetch dest
T ← LdF[DMA,16,2];*use StkP to index xBuf
XBI ← (XBI) + T, LoadPage[ConvertPage3];
StkP ← XBI, CallP[neCVor];
CycleControl ← RTemp, Skip[R>=0];
Goto[xnCVX];*odd; source exhausted
T ← WFA[AC3];*even; source contribution to 2nd dest word, done if 0
lu ← LdF[SStkP&NStkP,16,2], Goto[xnCVX,Alu=0];
Stack&+1, Goto[doSingleWord,Alu=0];*Go if not still in quadword
Stack ← (Stack) or T, Goto[xnCVX];*odd; OR the second Dest word

doSingleWord: PFetch1[DMA,XBI,1];
*even; fetch 2nd dest word
XBI ← (XBI) or T, LoadPage[ConvertPage1];*so XBI will be written
PStore1[DMA,XBI,1], Call[cvRT1toT];*UGH
xnCVX:
PStore4[DMA,xBuf,0];*even; store buffer
T ← RTemp1;*get NWRDS
DMA ← (DMA) + T;
SMA ← T ← (SMA) + 1, Goto[xnCVLOOP];

xnCNVEND:
LU ← AC3, LoadPage[nePage], Goto[.+2,R Odd];
AC3 ← Rsh[AC3,1], GotoP[neTask1st];
AC3 ← Rsh[AC3,1], GotoP[neTaskSkp];

OnPage[ConvertPage3];
neCVor:
CycleControl ← AC1;
T ← RF[AC3]; *source contribution to first dest word
Stack ← (Stack) or T, Return;

*Extended Opcodes with no Displacement or parameter
OnPage[xoPage];

DIR:
NWW ← (NWW) or (100000C), Goto[WRTRAM], At[xoTab0,0];*dir - 61000

EIR:
T ← (R400) or (52C), Goto[EIRcom], At[xoTab1,0];*eir - 61001
EIRcom:
PFetch1[MDS,WW], Task;
NWW ← (NWW) and not (100000C);
T ← (WW) and not (100000C);
NWW ← (NWW) or T, LoadPage[nePage];
PCF[IBuf], DblGotoP[EIRz,BRIy,R Odd];
OnPage[nePage];
*EIR must test for interrupts NOW. We simulate JMP .+1
EIRz:
T ← (PCF.word) + 1, Goto[PCJmp1];
BRIy:
T ← (R400) or (100C), Goto[JmpPzInd]; *fetch PC from location 500


BRI:
T ← (R400) or (52C), Goto[EIRcom], At[xoTab0,1] ;*bri - 61002


RCLK:
LoadPage[XMiscPage], At[xoTab1,1] ;*rclk - 61003
T ← (R400) or (30C), CallP[MXRClk];
AC1 ← T;
T ← RTemp, Goto[RCLK1];

SIO:
T ← AC0, LoadPage[EEPage], At[xoTab0,2];*sio
RTemp1 ← 0C, GotoP[EESIO]; *RTemp1=0 means Return to Nova

%BLT and BLKS:
AC0
address of first source word - 1 (BLT), or data to be stored (BLKS)
AC1
address of last destination word (= destination+word count-1)
AC2
unused
AC3
negative word count
%

:IF[neFastBltBlks];
*Fast versions moving quadwords

*Average timing for BLT’s longer than 8 words ~= 100 + 7.25*nwords cycles,
*assuming random alignment of source and destination and non-overlap case.
BLT:
T ← AC0, At[xoTab1,2];
T ← (AC3) - T, Task;*T ← - word count - source + 1
AC1 ← (AC1) + T;*AC1 ← destination-source
(AC1) and not (3C);
*Move the words one-at-a-time if destination address is 0 to 3 larger than
*the source address; restore AC1.
T ← AC1 ← (AC1) - T, LoadPage[neIntPage0], Skip[Alu#0];
AC3 ← (AC3) + (4C), GotoP[Blt1W];*Even
AC3 ← (AC3) + T, GotoP[.+1];*AC3 ← destination-1
OnPage[neIntPage0];
*Dispatch on two low bits of destination-1 to transfer single words until
*destination is quadaligned.
Dispatch[AC3,16,2];*Odd
AC3 ← (AC3) - T, Disp[.+1];*Restore AC3
AC0 ← T ← (AC0) + 1, Call[BltLp], At[BltTab,0];*01
AC0 ← T ← (AC0) + 1, Call[BltLp], At[BltTab,1];*10
AC0 ← T ← (AC0) + 1, Call[BltLp], At[BltTab,2];*11
*Destination quadaligned; setup loop.
LU ← AC3, Call[BltZT], At[BltTab,3];*00

*Loop begins here with AC3 .ne. 0
*Check for .gr. 4 words to transfer (i.e., AC3 # -4, -3, -2, or -1)
*Check for .ge. 4 is better but slows inner loop by 5 cycles.
AC3 ← (AC3) + (4C);
*Dispatch on low two bits of Source-1 to determine optimal fetch
Dispatch[AC0,16,2], Goto[Blt1W,Carry];
T ← (AC1) - (3C), Disp[.+1];*Even

PFetch4[AC0,xBuf,1], Goto[Blt4S],At[BltFTab,3];*00

*Smashes wBuf3
PFetch4[AC0,wBuf3,0],At[BltFTab,0];*01
PFetch1[AC0,xBuf3,4], Goto[Blt4S];

PFetch2[AC0,xBuf,1],At[BltFTab,1];*10
PFetch2[AC0,xBuf2,3], Goto[Blt4S];

*Smashes yBuf
PFetch4[AC0,xBuf1,2],At[BltFTab,2];*11
PFetch1[AC0,xBuf,1], Goto[Blt4S];

Blt4S:
AC0 ← (AC0) + (4C), Goto[Blks4S];

Blt1W:
AC3 ← (AC3) - (4C), Call[.+1];
AC0 ← T ← (AC0) + 1;
BltLp:
PFetch1[MDS,xBuf], Goto[BlksLp];

BltZT:
Skip[Alu#0];
LoadPage[nePage], Goto[BltXit];
Return;

*Average timing ~= 112 + 2.5*nwords cycles for nwords > 8
BLKS:
T ← AC0, LoadPage[neBlksPage0], At[xoTab0,3];
xBuf ← T, GotoP[.+1];
OnPage[neBlksPage0];
*Remoted for page packing
xBuf1 ← T;
xBuf2 ← T;
xBuf3 ← T, Task;
T ← AC1;
AC3 ← (AC3) + T, LoadPage[neIntPage0];*AC3 ← destination-1
*Dispatch on two low bits of destination-1 to transfer single words until
*destination is quadaligned.
Dispatch[AC3,16,2], GotoP[.+1];
OnPage[neIntPage0];
AC3 ← (AC3) - T, Disp[.+1];
LU ← AC3, Call[BlksLx], At[BlksTab,0];*01
LU ← AC3, Call[BlksLx], At[BlksTab,1];*10
LU ← AC3, Call[BlksLx], At[BlksTab,2];*11
*Quadaligned; setup loop--ensure word count .ne. 0
LU ← AC3, Call[BltZT], At[BlksTab,3];*00
*Loop here while .gr. 4 words to do
Blks4:
AC3 ← (AC3) + (4C);
T ← (AC1) - (3C), Goto[Blks1W,Carry];
Blks4S:
LU ← NWW, Skip[R>=0];*Even
PStore4[AC3,xBuf], Return;
PStore4[AC3,xBuf], DblGoto[intEnt,int0Ret,Alu#0];

*Store one word in xBuf, check for done, check for interrupts, and loop
Blks1W:
AC3 ← (AC3) - (4C), Call[BlksLx];*Odd
BlksLp:
LU ← AC3;
BlksLx:
T ← AC3 ← (AC3) + 1, Skip[Alu#0];
AC3 ← (AC3) - 1, LoadPage[nePage], Goto[BltXit];
PStore1[AC1,xBuf];
LU ← NWW, DblGoto[intDis,intEna,R<0];

:ELSE;
*Slower, smaller versions using single-word transfers
*Average timing is about 32 + 19*nwords cycles.
BLT:
AC0 ← T ← (AC0) + 1, LoadPage[nePage], At[xoTab1,2];
Call[neRet];*For tasking
PFetch1[MDS,xBuf], Call[BlksLp];
AC0 ← T ← (AC0) + 1, Goto[.-1];

*Average timing ~= 30 + 17*nwords cycles
BLKS:
T ← AC0, LoadPage[nePage], At[xoTab0,3];
xBuf ← T, Call[neRet];*For tasking
BlksLp:
LU ← AC3, LoadPage[neIntPage0];
T ← AC3 ← (AC3) + 1, SkipP[Alu#0];
OnPage[neIntPage0];
AC3 ← (AC3) - 1, LoadPage[nePage], Goto[BltXit];
PStore1[AC1,xBuf];
LU ← NWW, DblGoto[intDis,intEna,R<0];
:ENDIF;

BltXit:
CSkipData, GotoP[neTask1st];

JMPRAM:
T ← 20C, At[xoTab0,4] ; *jmpram - 61010
LU ← (RHMask[AC1]) xor T;
T ← AC0, Skip[Alu=0] ;
BreakPoint, Return; *Should never get here
LoadPage[7];
GotoP[MStart];

RDRAM:
AC0 ← (Zero) - 1, At[xoTab1,4];*rdram - 61011
WRTRAM:
CSkipData, Return, At[xoTab0,5];*wrtram - 61012 (nop)

DIRS:
CSkipData, At[xoTab1,5];
LoadPage[nePage];
NWW ← (NWW) or (100000C), DblGoto[neTask1st,neTaskSkp,R<0];

VERS:
AC0 ← (40000c), Goto[WRTRAM], At[xoTab0,6] ;*vers - 61014


*AC0,,AC1 ← (AC1 * AC2) + (AC0)
*Steps:
*1
test loop count for done
*2
test next mpr bit (AC1[17]), Rsh AC1
*2a
if 1:AC0 ← AC0 + T
*3a
Rsh AC0, or’ing 100000 into AC0 if add carried
*2b
if 0:Rsh AC0
*4a,3b
or 100000 into AC1 if shifted a 1 out of AC0

xoMul:
T ← AC2, LoadPage[neMulPage], At[xoTab0,10];
RTemp ← 16C, GotoP[.+1];*setup loop
OnPage[neMulPage];
Call[xoMul1];
RTemp ← (RTemp) - 1, Goto[.+3,R>=0];
LoadPage[nePage];
CSkipData, GotoP[neTask1st];
*Loop time: 8 to 9 cycles on multiplier zeroes, 13 to 15 on multiplier ones
xoMul1:
AC1 ← Rsh[AC1,1], Skip[R Odd];
AC0 ← Rsh[AC0,1], DblGoto[xoMula,xoMulb,R Odd];
AC0 ← (AC0) + T;
AC0 ← Rcy[AC0,1], Skip[Carry];
AC0 ← (AC0) and not (100000C), DblGoto[xoMula,xoMulb,Alu<0];
AC0 ← (AC0) or (100000C), DblGoto[xoMula,xoMulb,Alu<0];

xoMula:
AC1 ← (AC1) or (100000C), Return;
xoMulb:
Return;

*AC0,,AC1/AC2. Quotient in AC1, remainder in AC0
xoDiv:
LoadPage[neDivPage], T ← AC2, At[xoTab1,10];
LU ← (AC0) - T, GotoP[.+1];
OnPage[neDivPage];
RTemp ← 16C, Goto[.+3,Carry’];
RTemp ← (RTemp) + 1, LoadPage[nePage];*RTemp odd--no-skip
xoDivX:
RTemp, CSkipData, DblGoto[neTask1st,neTaskSkp,R Odd];
T ← 31C;
SAluf ← T;*SAluf ← A+A+1
T ← (AC2) + (0C);*T ← divisor, carry ← 0
AC1 ← (AC1) SAlufOp T, UseCOutAsCIn, Call[xoDivE];
*Loop time: 13 to 15 cycles/bit
LU ← RTemp1;
AC0 ← (AC0) - T, Skip[Alu>=0];
AC1 ← (AC1) SAlufOp T, Goto[xoDivL];*No carry test--quot ← 1
AC1 ← (AC1) SAlufOp T, UseCOutAsCIn, Skip[Carry];*Subtract ok?
AC0 ← (AC0) + T, FreezeResult;*No--undo
xoDivL:
RTemp ← (RTemp) - 1, FreezeResult, Skip[R>=0];
LoadPage[nePage], Goto[xoDivX];*RTemp even--skip
xoDivE:
AC0 ← (AC0) SAlufOp T, UseCOutAsCIn, Skip[R<0];
RTemp1 ← Zero, Return;
RTemp1 ← (RTemp1) or not (0C), Return;

*AC0,,AC1/AC2. Quotient in AC1, remainder in AC0
%DIV:
LoadPage[MulDivPage], T ← AC2, At[xoTab1,10];
CallP[Divide], LU ← (AC0) - T;*div
LoadPage[nePage];
LU ← neCNT, CSkipData, DblGoto[neTask1st,neTaskSkp,R Odd];

OnPage[MulDivPage];
Divide:
DblGoto[noDiv,doDiv,carry], neCNT ← 17C;
noDiv:
Return; *neCNT odd means no skip

doDiv:
UseCTask;
T ← APCTask&APC;
RTemp1 ← T; *save link
T ← AC2, Call[UDIVenter];

lu ← Rcy[RTemp,1]; *loop Returns to here
AC0 ← (AC0) - T, DblGoto[UDIV1t,UDIV1f,ALU<0]; *test flag

UDIV1t:
AC1 ← (Lsh[AC1,1]) + 1, DblGoto[UDIV3t,UDIV3f,R<0]; *no need to test carry, quot ← 1
UDIV1f:
DblGoto[UDIV2t,UDIV2f,carry]; *subtract ok, test carry

UDIV2t:
AC1 ← (Lsh[AC1,1]) + 1, DblGoto[UDIV3t,UDIV3f,R<0]; *put a one in the quotient
UDIV2f:
AC0 ← (AC0) + T; *no carry - undo subtraction
UDIVenter:
AC1 ← (Lsh[AC1,1]), DblGoto[UDIV3t,UDIV3f,R<0]; *put a Zero in the quotient

UDIV3t:
neCNT ← (MNBR ← neCNT) - 1, Skip[R>=0];
APC&APCTask ← RTemp1, Goto[UDIV4f];
AC0 ← (Lsh[AC0,1]) + 1, DblGoto[UDIV4t,UDIV4f,R<0];

UDIV3f:
neCNT ← (MNBR ← neCNT) - 1, Skip[R>=0];
APC&APCTask ← RTemp1, Goto[UDIV4f];
AC0 ← (Lsh[AC0,1]), DblGoto[UDIV4t,UDIV4f,R<0];

UDIV4t:
RTemp ← (RTemp) or (1C), Return; *set flag
UDIV4f:
RTemp ← (RTemp) and not (1C), Return; *clear flag
%

AWMDS:
T ← AC0, LoadPage[neFixBPage], At[xoTab0,11];
T ← (Lsh[AC0,10]) or T, CallP[FixNBases];
LoadPage[XMiscPage], MDShi ← T;
CallP[SetIOBases];*In MesaX
LoadPage[nePage];
xoExit:
CSkipData, GotoP[neTask1st];

*Enter bbBitBLT with StkP pointing at AC1 (icom), pointer to BitBlt table in
*AC2, and (Cycle&PCXF) and not (100000C) in T.
ABITBLT:
LoadPage[bbPage], At[xoTab0,12];
T ← (Cycle&PCXF) and not (100000C), GotoP[bbBitBLT];

xoLRJ:
T ← AC0, LoadPage[neLRJPage], At[xoTab0,17];
LP ← T, GotoP[.+1];
OnPage[neLRJPage];
*AC1 odd: turn off tasking, do inline storage refresh; load control store,
*
jump to starting address in the end item of the RAM image.
*AC1 even: normal tasking; ignore starting address, continue with next item.
T ← (AC1) or (100000C);
T ← (Rsh[AllOnes,17]) xor T;
RTemp1 ← T;*RTemp1<0 = call from Alto emulator, odd = resume
*at JmpFin, even = jump to starting address
T ← (Rsh[AllOnes,17]) and T;
xfTemp1 ← T;
RTemp ← FFaultAdd;
StkP ← RTemp, Task;
Stack ← (Stack) and not (1C);
T ← MDShi, LoadPageExternal[LRJPage];
LPhi ← T, GotoExternal[LRJStart];

SDP:
LoadPage[XMiscPage], At[xoTab1,17];
T ← AC0, CallP[MXPar]; *In MesaX
RCLK1:
AC0 ← T, LoadPage[nePage], Goto[xoExit];

:IF[neBCPL300];

OnPage[nePage];

*Arrive at brJsrPz on a JSR 200 to 377 with Efadr - 300 through the ALU.
brJsrPz:
LU ← PCF[IBuf] - (333C), Skip[Alu>=0];*Even
PFetch4[MDS,IBuf], Goto[JsrFin];*.ls. 300
LoadPage[brJsrPage], Skip[Alu<0];
LoadPage[nePage], GotoP[brJsrExit];*.ge. 333
Dispatch[PCF[IBuf],13,4], DblGotoP[br300Odd,br300Even,R Odd];

OnPage[brJsrPage];

brJsrExit:
PFetch4[MDS,IBuf], GotoP[JsrFin];

brJsrSNQ0:
LoadPage[nePage];
PFetch1[AC1,RTemp,0], GotoP[brSNQ0jsr];

brJsrSNQ1:
LoadPage[nePage];
PFetch1[AC0,RTemp,0], GotoP[brSNQ1jsr];

br300Odd:
CSkipData, Disp[.+1];
AC1 ← Rsh[AC1,6], Return, At[Bcpl300Odd,0];*301
AC1 ← Rsh[AC1,5], Return, At[Bcpl300Odd,1];*303
AC1 ← Rsh[AC1,4], Return, At[Bcpl300Odd,2];*305
AC1 ← Rsh[AC1,3], Return, At[Bcpl300Odd,3];*307
AC1 ← Rsh[AC1,2], Return, At[Bcpl300Odd,4];*311
AC1 ← Rsh[AC1,1], Return, At[Bcpl300Odd,5];*313
T ← AC0 ← Lsh[AC0,7], Goto[brJsrSNQ0], At[Bcpl300Odd,6];*315
T ← AC0 ← Lsh[AC0,6], Goto[brJsrSNQ0], At[Bcpl300Odd,7];*317
T ← AC0 ← Lsh[AC0,5], Goto[brJsrSNQ0], At[Bcpl300Odd,10];*321
T ← AC0 ← Lsh[AC0,4], Goto[brJsrSNQ0], At[Bcpl300Odd,11];*323
T ← AC0 ← Lsh[AC0,3], Goto[brJsrSNQ0], At[Bcpl300Odd,12];*325
T ← AC0 ← Lsh[AC0,2], Goto[brJsrSNQ0], At[Bcpl300Odd,13];*327
T ← AC0 ← Lsh[AC0,1], Goto[brJsrSNQ0], At[Bcpl300Odd,14];*331

br300Even:
CSkipData, Disp[.+1];
AC0 ← Rsh[AC0,6], Return, At[Bcpl300Even,0];*300
AC0 ← Rsh[AC0,5], Return, At[Bcpl300Even,1];*302
AC0 ← Rsh[AC0,4], Return, At[Bcpl300Even,2];*304
AC0 ← Rsh[AC0,3], Return, At[Bcpl300Even,3];*306
AC0 ← Rsh[AC0,2], Return, At[Bcpl300Even,4];*310
AC0 ← Rsh[AC0,1], Return, At[Bcpl300Even,5];*312
Return, At[Bcpl300Even,6];*314 (nop)
T ← AC1 ← Lsh[AC1,7], Goto[brJsrSNQ1], At[Bcpl300Even,7];*316
T ← AC1 ← Lsh[AC1,6], Goto[brJsrSNQ1], At[Bcpl300Even,10];*320
T ← AC1 ← Lsh[AC1,5], Goto[brJsrSNQ1], At[Bcpl300Even,11];*322
T ← AC1 ← Lsh[AC1,4], Goto[brJsrSNQ1], At[Bcpl300Even,12];*324
T ← AC1 ← Lsh[AC1,3], Goto[brJsrSNQ1], At[Bcpl300Even,13];*326
T ← AC1 ← Lsh[AC1,2], Goto[brJsrSNQ1], At[Bcpl300Even,14];*330
T ← AC1 ← Lsh[AC1,1], Goto[brJsrSNQ1], At[Bcpl300Even,15];*332

:ENDIF;

:IF[neBCPLI340];

OnPage[nePage];

*BCPL Runtime: JSR @ 340-357
br340Disp:
Dispatch[PCF[IBuf],14,4], GotoP[.+1];
OnPage[br340Page];
T ← AC1, Disp[.+1];
AC0 ← (AC0) or T, Goto[WRTRAM], At[neBR340,0]; *AC0←AC0 or AC1
AC0 ← (AC0) xor T, Goto[WRTRAM], At[neBR340,1]; *AC0←AC0 xor AC1
AC0 ← (AC0) xnor T, Goto[WRTRAM], At[neBR340,2]; *AC0←AC0 xnor AC1
T ← PCF[IBuf], LoadPage[nePage], Goto[br340NI], At[neBR340,3]; *Mult
T ← PCF[IBuf], LoadPage[nePage], Goto[br340NI], At[neBR340,4]; *DivRem
T ← PCF[IBuf], LoadPage[nePage], Goto[br340NI], At[neBR340,5]; *DivRem
T ← (AC1) - (20C), DblGoto[brLshNeg,brLshPos,Alu<0], At[neBR340,6]; *AC0 ← AC0 lsh AC1
T ← (AC1) - (20C), DblGoto[brRshNeg,brRshPos,Alu<0], At[neBR340,7]; *AC0 ← AC0 rsh AC1
CSkipData, Goto[brBranch], At[neBR340,10]; *Switchon branch
CSkipData, Goto[brLookup], At[neBR340,11]; *Switchon lookup
T ← PCF[IBuf], LoadPage[nePage], Goto[br340NI], At[neBR340,12]; *Util (swats)
T ← PCF[IBuf], LoadPage[nePage], Goto[br340NI], At[neBR340,13]; *Finish
T ← PCF[IBuf], LoadPage[nePage], Goto[br340NI], At[neBR340,14]; *Abort
CSkipData, Goto[brLongJump], At[neBR340,15]; *Long jump
T ← PCF[IBuf], LoadPage[nePage], Goto[br340NI], At[neBR340,16]; *GetLV (swats)
T ← PCF[IBuf], LoadPage[nePage], Goto[br340NI], At[neBR340,17]; *MulPlus

br340NI:
PFetch1[MDS,RTemp], GotoP[JsrIndFin];

*These don’t contribute significantly to performance.
brLshNeg:
AC1 ← (AC1) + (17C), Goto[brLshNeg1];*AC1 ← 17b - rsh count
brLshPos:
AC1 ← (Zero) - T - 1;*AC1 ← 17b - lshift count
brRshNeg1:
CycleControl ← AC1, CSkipData, Skip[Alu>=0];
AC0 ← 0C, Return;*Lsh count > 17b
AC0 ← WFA[AC0], Return;*Lsh count = 0 to 17b

brRshNeg:
AC1 ← (AC1) + (17C), Goto[brRshNeg1];
brRshPos:
AC1 ← (Zero) - T - 1, Skip[Alu<0];*AC1 ← 17b - rsh count
AC0 ← 0C, Goto[WRTRAM];*Rshift count > 17b
brLshNeg1:
CycleControl ← AC1, CSkipData, Skip[Alu>=0];
AC0 ← 0C, Return;*Rsh count = 0, lsh count < -17b
AC0 ← RF[AC0], Return;*Rsh count = 1 to 17b

br340AC0toT:
T ← AC0, Return;

%Branch: "switchon" implemented by dispatch.
jsr @350; with case value in AC0
value of last case
number of cases
lastTarget-.
...
firstTarget-.
continue here if out of range, AC0 unchanged
%
brBranch:
CSkipData, Call[br340AC0toT];*Point PCF at odd byte of last case value
*T ← last case value - switchon value
T ← PCF[IBuf] - T;
CSkipData, Skip[Carry];
SkipData, Call[brBrn1];*.gr. last case; fake call
SkipData;*Point PCF at odd byte of no. cases; fake call
*LU ← no. cases - (last case value - switchon value) - 1 =
*LU ← switchon value - (last case value - no. cases + 1) =
*LU ← switchon value - first case value
LU ← PCF[IBuf] - T - 1;
T ← (PCF.word) + T + 1, Goto[brBrn1,Carry’];
PFetch1[PC,RTemp];*Fetch self-rel ptr to new address
T ← T, LoadPage[nePage];*Bypass kludge
T ← (RTemp) + T, GotoP[brJmpPz];

brBrn1:
T ← PCF[IBuf] + 1, LoadPage[nePage];
brLk1:
T ← PCF[RZero] + T, GotoP[PCJmp1];*Jump to out-of-range


%Switchon "lookup"; calling sequence as follows:
jsr @351; with case value in AC0
number of cases
case value 1
target1-.
...
case value n
targetn-.
continue here if not found, AC0 unchanged.
%
brLookup:
SkipData;*Point PCF at odd byte of no. cases; may refill
T ← PCF[IBuf] + 1;
RTemp ← T, CSkipData, Call[br340AC0toT];
*Have PCF pointing at even byte of case value j, value being looked up in T
CSkipData;*Point PCF at odd byte of case value j; may refill
RTemp ← (RTemp) - 1;
LU ← PCF[IBuf] - T, Skip[Alu#0];
T ← RZero, LoadPage[nePage], Goto[brLk1];
CSkipData, Goto[aoSkip,Alu#0];*Point PCF at even byte of targetj
%Long jump; calling sequence:
jsr @355
target-.
%
brLongJump:
SkipData;
T ← PCF[IBuf], LoadPage[nePage], Goto[brLk1];

:ENDIF;

:IF[neBCPLI360];

OnPage[nePage];

*Arrive at JsrPzInd on Jsr @ 200-377; have EfAdr in T and in PCF[IBuf];
:IF[neBCPLI340];
*LU ← PCF[IBuf] - (340C) is pending; check for BCPL runtime
JsrPzInd:
LU ← PCF[IBuf] - (360C), Skip[Alu>=0];
PFetch1[MDS,RTemp], Goto[JsrIndFin];*.ls. 340
LU ← PCF[IBuf] - (371C), Skip[Alu>=0];
LoadPage[br340Page], Goto[br340Disp];*340-357
:ELSE;
*LU ← PCF[IBuf] - (360C) is pending; check for BCPL runtime
JsrPzInd:
LU ← PCF[IBuf] - (371C), Skip[Alu>=0];
PFetch1[MDS,RTemp], Goto[JsrIndFin];
:ENDIF;
Dispatch[PCF[IBuf],14,4], Goto[JsrPzIF,Alu>=0];
CSkipData, Disp[brJsrI360];*360-370

brJsrI360:
PFetch1[AC1,RTemp,0], Goto[brSNQ0], At[neBR360,0]; *SNQ0
PFetch1[AC0,RTemp,0], Goto[brSNQ1], At[neBR360,1]; *SNQ1
T ← (AC1) and (100000C), Goto[brLY01], At[neBR360,2]; *LY01
T ← (AC0) and (100000C), Goto[brLY10], At[neBR360,3]; *LY10
PFetch1[AC2,RTemp,3], Goto[brSY01], At[neBR360,4]; *SY01
PFetch1[AC2,RTemp,3], Goto[brSY10], At[neBR360,5]; *SY10
PFetch1[AC2,AC2,0], Goto[brReturn], At[neBR360,6]; *Return
T ← PCF[IBuf], Goto[JsrPzIF], At[neBR360,7]; *StArgs (never xct)
%GetFrame/StArgs is usually in the context:
sta 3 1 2
jsr @GetFrame
Frame size
jsr @StArgs
and is equivalent to the following pseudo-program:
oldAC2 ← AC2;
T ← AC2 - [PC+1] - 2;
if [335] le T then swat (normal runtime does the swat)
AC2 ← T;
sta 0 4 2; Save arg1
sta 1 5 2; Save arg2
sta oldAC2 0 2; Save old frame ptr
AC0 ← [[oldAC2+1]]; AC0 ← nargs passed
if AC0 < 3 then dblskip exit
Temp ← [oldAC2+3]; Temp ← arg3/frame rel ptr to extra args
if AC0 eq 3 then sta Temp 6 2
else Move AC0-2 words from oldAC2 + Temp + 3 to AC2 + 6.
dblskip exit
%
brGetFrame:
T ← 335C, Call[brFetToRTemp], At[neBR360,10];*RTemp ← stack limit
T ← AC2;*DMA ← oldAC2
DMA ← T, SkipData, Call[.+1];*Point PCF at odd byte of frame size (fake call)
PFetch1[AC2,RTemp1,1];*RTemp1 ← [oldAC2+1]
*Allocated frame must be 2 larger for ancient BCPL programs
T ← PCF[IBuf] + 1, LoadPage[brGarbPage0];*T ← frame size + 1
T ← (AC2) - T - 1, CallP[brGF1];*T ← AC2 - frame size - 2 = new frame ptr
CSkipData, Call[brCSret];*Point PCF at even byte of next opcode
PStore1[AC2,AC0,4], Task;*Save arg1
T ← RTemp1;
PFetch1[MDS,AC0], Goto[.+3,BPCChk’];*AC0 ← [[oldAC2+1]] = nargs passed
LoadPage[0];
PFetch4[PC,IBuf,4], Call[neRefx];
PStore1[AC2,AC1,5];*Even; Save arg2
T ← (AC0) - (3C);
RTemp ← T, Skip[Alu>=0];*RTemp ← args to move
Goto[neTask1st];*<=2 args--exit
T ← (xBuf) + (3C), Skip[Alu=0];*Even; skip if exactly 3 args
PFetch1[DMA,xBuf];*Odd; >3 args
DMA ← T;*Even; bypass kludge if it matters
T ← 6C, Call[neRet];
brGFlp:
PStore1[AC2,xBuf];
RTemp ← (RTemp) - 1;
T ← (Zero) + T + 1, Skip[Alu>=0];
Goto[neTask1st];*Exit
PFetch1[DMA,xBuf,1];
DMA ← (DMA) + 1, Return;

OnPage[brGarbPage0];
brGF1:
LU ← (RTemp) - T - 1;*LU ← stklim - new frame pointer
*xBuf ← arg3/frel ptr to xargs
PFetch1[DMA,xBuf,3], Goto[brGFok,Carry’];
PC ← (PC) - 1, LoadPage[nePage];
T ← 370C, GotoP[JsrPzIF];*Stack ovf--let software do it
brGFok:
AC2 ← T, CSkipData;*PCF now points at even byte of Jsr @StArgs
PStore1[AC2,DMA,0], Return;*Save old frame ptr at [AC2]

OnPage[nePage];

brCSret:
CSkipData, Return;

brSNQa:
T ← PCF[IBuf], LoadPage[brGarbPage2];*T ← mask
RTemp ← (RTemp) and not T, GotoP[.+1];
OnPage[brGarbPage2];
T ← (RTemp1) and T;
RTemp ← (RTemp) or T, Return;
OnPage[nePage];

*SNQ0 executes @AC1 ← (@AC1 & not mask) or (AC0 & mask) where the mask
*is [PC+1] and continues at PC+2.
brSNQ0:
T ← AC0;
brSNQ0jsr:
*Enter here from JSR 300-332 opcodes also
RTemp1 ← T, CSkipData, Call[brSNQa];*May refill IBuf
PStore1[AC1,RTemp,0], Goto[neCS1st];

*SNQ1 is like SNQ0 with AC0 and AC1 interchanged.
brSNQ1:
T ← AC1;
brSNQ1jsr:
*Enter here from JSR 300-332 opcodes also
RTemp1 ← T, CSkipData, Call[brSNQa];
PStore1[AC0,RTemp,0], Goto[neCS1st];

*Return right-justified in AC0 the AC1th byte from the array pointed to by
*AC0 (Note: AC1 may be negative).
brLY01:
T ← (Rsh[AC1,1]) + T, Goto[.+3,R Odd];
PFetch1[AC0,AC0];
AC0 ← LdF[AC0,0,10], Return;
PFetch1[AC0,AC0];
AC0 ← LdF[AC0,10,10], Return;

*Like LY01 with AC0 and AC1 interchanged
brLY10:
T ← (Rsh[AC0,1]) + T, Goto[.+3,R Odd];
PFetch1[AC1,AC1];
AC1 ← LdF[AC1,0,10], Return;
PFetch1[AC1,AC1];
AC1 ← LdF[AC1,10,10], Return;

brFetToRTemp:
PFetch1[MDS,RTemp], Return;

brTtoDMA:
DMA ← T, Return;*Bypass kludge

brSYe:
T ← Lsh[RTemp,10];
RTemp1 ← (RHMask[RTemp1]) or T;
brSYx:
PStore1[DMA,RTemp1,0], Goto[neTask1st];
brSYo:
T ← RHMask[RTemp];
RTemp1 ← (LHMask[RTemp1]) or T, Goto[brSYx];

*Store the byte at AC2!3 into the AC1th byte of the array pointed to by
*AC0 (Note: AC1 may be negative).
brSY01:
T ← (AC1) and (100000C);
T ← (Rsh[AC1,1]) + T;
PFetch1[AC0,RTemp1], Call[brTtoDMA];
AC1, DblGoto[brSYo,brSYe,R Odd];

*Like SY01 with AC0 and AC1 interchanged.
brSY10:
T ← (AC0) and (100000C);
T ← (Rsh[AC0,1]) + T;
PFetch1[AC1,RTemp1], Call[brTtoDMA];
AC0, DblGoto[brSYo,brSYe,R Odd];

*Return: AC2 ← AC2!0; PC ← (AC2!1)+1
brReturn:
T ← (AC2) + 1, Call[brFetToRTemp];
T ← (RTemp) + 1, Goto[brJmpPz];

:ENDIF;

:END[Nova];