:Title[LCALLRET];
*
* Edit History
* March 13, 1985 9:45 AM, Masinter, remove calls to SAVEUCODESTATE
* January 6, 1985 12:18 AM, JonL, let .ATOMICFN flipMembase when
* litatom index number has the 2↑15 bit on
* February 9, 1984 1:07 AM, JonL, fixed screwup in label ufnPC:
* February 2, 1984 11:04 AM, JonL, fixes to callers of SAVEUCODESTATE
* January 31, 1984 5:02 PM, temporarily add call to SAVEUCODESTATE
*to opUFN, ufnPC, and callers of DOCALLPUNT
* January 24-27, 1984, JonL, Globalize DOCALLPUNT
* January 13, 1984 8:07 PM, JonL, call and return code into one file
* January 4, 1984 7:26 PM, JonL, moved in some subroutines from
*LSTACK.mc -- ADDSTK from LSTACK; ufnPC resets Hardware stack
* December 31, 1983 12:51 PM, JonL, set memBase at ufnPC so code can
*branch directly to it; added some commentary
* November 29, 1983 2:42 PM, JonL, removed spurious BrLo← DEFLO.
* December 7, 1982 4:38 PM, Masinter - - -
*--------------------------------------------------------------------
* Function call
*--------------------------------------------------------------------
KnowRBase[LTemp0];
TOPLEVEL;
InsSet[LispInsSet, 1];
*--------------------------------------------------------------------
opFN:* FN0-4 operators
*--------------------------------------------------------------------
NARGS← Id;
T← Id;
T← LSH[T,10];
DEFLO← (Id) + T;* 16 bit atom index
*--------------------------------------------------------------------
.FNCALL1:* Entry for DOCALLPUNT
*--------------------------------------------------------------------
LTEMP0← Id - (PCX’) - 1;* Return PC, for a n-byte op
CHECKPCX;
*--------------------------------------------------------------------
.FNCALL2:* Entry for FNx and opUFN
*--------------------------------------------------------------------
T← (PVAR) - (FXBACK[PC]);* Suspend the current frame
store← T, dbuf← LTEMP0, Branch[.ATOMICFN];* by saving the PC
.atfXtnd:
memBase← StackBR, Call[ADDSTK];
*--------------------------------------------------------------------
.ATOMICFN:* Build a frame and start running the function whose
*index is DEFLO; NARGS args are on stack already.
*--------------------------------------------------------------------
T← (DEFLO) + (DEFLO), memBase← DefBR;* T← word index of defcell
PSTATE← T-T-1, branch[.+2, carry’];
flipMemBase;
* CAN FAULT!!!
T← (FETCH← T) + 1;* Fetch contents of defcell
LTEMP0← MD, fetch← T, T← (rhmask);* LTEMP0← hi def
branch[.+2, R<0], LTEMP0← T and (LTEMP0),* SignBit of defcell is
T← Md, memBase← ifuBR; * flag for compiled code
DEFHI← (atomHiVal), Branch[.notCCODE];
BrHi← LTEMP0;
LTEMP1← BrLo← T;* LTEMP1← fnLo
* CAN FAULT!!!
FETCH← 0s;* Fetch first word of
T← LSH[LTEMP0, 10];* function header
LTEMP0← (LTEMP0) + T;* Recompute fnheader
T← MD, fetch← 1s;
T← (ESP) - T;
pd← T - (TSP);* ESP - #WORDS - TSP
branch[.+2, carry], LTEMP2← Md,* LTEMP2← def.na
T← (fetch← 2s) + 1;
DEFHI← (atomHiVal), Branch[.atfXtnd];
:if[FNStats];
branch[.nofnstat, R<0], LTEMP3← Md,
FnStatsPtr, fetch← T; * LTEMP3← def.pv
PCF← Md, PSTATE← A0; call[FNSTAT];
branch[.afterfnstat];
:else;
LTEMP3← Md, fetch← T;* LTEMP3← def.pv
:endif;
.nofnstat:
PCF← Md, PSTATE← A0;* start IFU early
.afterfnstat:
* No faults after here
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* KLUDGE FOR FINDING OUT WHO IS CALLED: SMASH DEF WITH BIT *
* FETCH← (4S); IVAR← MD; *
* BRANCH[.+2, R<0], IVAR← IVAR OR (100000C); *
* STORE← (4S), DBUF← IVAR; *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
T← (NARGS) + (NARGS), memBase← StackBR;
PCXBAD;
IVAR← (TSP) - T;
T← (PVAR) - (FXBACK[NEXT]);
store← T, dbuf← IVAR;* store FX.next
branch[.NoAdj, R<0], T← LTEMP2;
T← (NARGS) - T;
.tryagain:
branch[.NoAdj’, alu=0], pd← T;
branch[.TooMany, alu>0];
TSP← (store← TSP) + 1, dbuf← 0c;
TSP← (store← TSP) + 1, dbuf← 0c;
T← T+1, branch[.tryagain];
.TooMany:
TSP← (TSP) - (2c);
T← T-1, branch[.tryagain];
.NoAdj’:
Branch[.+2], pd← (TSP) and (2c);
.NoAdj:
pd← (TSP) and (2c);
branch[.QuadP, alu=0], T← (store← TSP) + 1, dbuf← BFBlock;
T← (store← TSP) + 1, dbuf← 0c;* Smash in a cell of 0’s if not
T← (store← T) + 1, dbuf← 0c;* quadword aligned; new BF wd
T← (store← T) + 1, dbuf← (add[BFBlock!, BFPadded!]c);
.QuadP:
T← (store← T) + 1, dbuf← IVAR;* new IVAR
T← (store← T) + 1, dbuf← FxtnBlock;* default flags
T← (store← T) + 1, dbuf← PVAR;* old PVAR
T← (store← T) + 1, dbuf← LTEMP1;* fn address hi
store← T, dbuf← LTEMP0;* fn address lo
T← PVAR← T + (FXDIF[PVAR, DEFHI]);
dblbranch[.StorePVS, .endfn, R>=0], Cnt← LTEMP3;
.StorePVS:
T← (store← T) + 1, dbuf← AllOnes;* "Pvars", in multiples
T← (store← T) + 1, dbuf← AllOnes;* of 2 cells
T← (store← T) + 1, dbuf← AllOnes;
T← (store← T) + 1, dbuf← AllOnes,
dblbranch[.StorePVS, .endfn, Cnt#0&-1];
.endfn:
T← TSP← T + (4c);
T← ((ESP) - T) rsh 1;
LEFT← T - (LeftOffset), NextOpCode;
.notCCODE:
T← (TSP), memBase← StackBR;
T← (store← T) + 1, dbuf← DEFHI;
TSP← (store← T) + 1, dbuf← DEFLO;
NARGS← (NARGS) + 1;
DEFLO← AT.INTERPRETER, branch[.ATOMICFN];
*--------------------------------------------------------------------
SUBROUTINE;ADDSTK: * add space to stack frame for FNCALL etc
*--------------------------------------------------------------------
T← (fetch← ESP) + 1;* next stack word
T← Md, fetch← T;
pd← T xor (FreeStackBlock);
branch[.+2, alu=0];
TOP LEVEL;Branch[STKOVPUNT]; TOPLEVEL;
ESP← (ESP) + (Md);
.mergefree:
T← (fetch← ESP) + 1;
T← Md, fetch← T;
pd← T xor (FreeStackBlock);
branch[.+2, alu=0], T← ESP;
LEFT← T - (TSP), Branch[FIXLEFT1];
ESP← (ESP) + (Md), branch[.mergefree];
TOPLEVEL;
IFUpause[10, 3, StackBR, 0, opFN, 0, 0, 0];*FN0
IFUpause[11, 3, StackBR, 0, opFN, 1, 0, 0];*FN1
IFUpause[12, 3, StackBR, 0, opFN, 2, 0, 0];*FN2
IFUpause[13, 3, StackBR, 0, opFN, 3, 0, 0];*FN3
IFUpause[14, 3, StackBR, 0, opFN, 4, 0, 0];*FN4
*--------------------------------------------------------------------
opFNX:
*--------------------------------------------------------------------
* Takes 3 argument bytes; first is NARGS, 2nd and 3rd are fn #.
* since IFU won’t handle 4 byte instructions, the first arg is
* gotten from the IFU, and the fn is fetched directly. Things are
* much simpler if the opcode happens to be word aligned.
NARGS← Id;
DEFLO← T← (Id)-(PCX’)-1;* Id is length- get byte# of 3rd byte
LTEMP0← T rsh 1;* word which contains hi byte of fn
PAGEFAULTOK;
LTEMP0← (FETCH← LTEMP0) + 1;
branch[.+2, R odd], DEFLO← MD,
T← T + (2c);* T has new PC
LTEMP0← T, memBase← StackBR, branch[.FNCALL2];
FNXsplit:
LTEMP0← T, FETCH← LTEMP0;* save PC, fetch lo byte
memBase← StackBR, T← MD;* T has lo byte of fn in hi byte
PAGEFAULTNOTOK;
DEFLO← Rcy[DEFLO, T, 10], branch[.FNCALL2];* and fix up
IFUpause[15, 2, ifuBR, 0, opFNX, noNData, 0, 0];
*--------------------------------------------------------------------
opAPPLYFN:
*--------------------------------------------------------------------
* TOS = FN TO CALL, TOS-1 = NARGS, TOS-... = arguments to FN
T← (fetch← TSP) + 1;* fetch defhi
DEFHI← Md, T← (fetch← T) - (3c);* fetch deflo
DEFLO← Md, T← (fetch← T) + 1;* fetch narghi
T← Md, fetch← T, flipMemBase;
NARGS← Md, pd← T xor (SmallHi);
branch[.+2, alu=0], TSP← (TSP) - (4c);
UCodeCheck[BadRetCall];
LTEMP0← Id - (PCX’) - 1;* Save return PC
T← (PVAR) - (FXBACK[PC]);
store← T, dbuf← LTEMP0;
pd← (DEFHI) xor (AtomHiVal);* Check for atomic fn
branch[.+2, alu=0];
branch[.notCCODE];
branch[.ATOMICFN];
IFUpause[16, 1, StackM2BR, 0, opAPPLYFN, NoNData, 0, 0];*APPLYFN
:if[NotReduced];
*--------------------------------------------------------------------
opCKAPPLY:
*--------------------------------------------------------------------
* TOS = FN TO CALL
T← (fetch← TSP) + 1;
LTEMP0← Md, fetch← T;* hiloc
T← Md, memBase← DefBR, pd← LTEMP0;
branch[.+2, alu=0], T← T + T;
CallUFN;* not litatom
PAGEFAULTOK;
FETCH← T;
LTEMP0← MD;
PAGEFAULTNOTOK;
branch[.+2, R<0], pd← (LTEMP0) and (20000c);
CallUFN;* not CCODEP
branch[.+2, alu=0];
CallUFN;* not argtype=0, 2
NextOpCode;
regOP1[17, StackM2BR, opCKAPPLY, NoNData];*CKAPPLY
:else;
UfnOps[17];
:endif;
*--------------------------------------------------------------------
opUFN:
*--------------------------------------------------------------------
* All "undefined" entries in the IFU memory come here, with
*a call is manufactured to the function fetched
* from the UFN table, according to byte at PC.
* Format of table:defindex[0:15]left word;
*nargs[8:15]right word
.ufn0:
memBase← ifuBR;
T← LTEMP1← not(PCX’);* T← current PC (byte offset)
LTEMP0← T rsh 1;* LTEMP0← current PC word address
CHECKPCX;
PAGEFAULTOK;
LTEMP0← (fetch← LTEMP0) + 1;* fetch word containing current op
T← Md, fetch← LTEMP0;
Branch[.ufnPCR, R odd], LTEMP1, LTEMP1← Md;
.ufnPCL:
LTEMP1← RCY[T, LTEMP1, 10];
T← RSH[T, 10], branch[.ufnPC2];
.ufnPCR:
T← (T) and (rhmask);
.ufnPC2:
memBase← ufnBR, T← T + T;
PAGEFAULTNOTOK;
T← (fetch← T) + 1;
DEFLO← Md, fetch← T;
NARGS← Md, memBase← StackBR;
T← RSH[NARGS, 10];
LTEMP0← BDispatch← T;
NARGS← (NARGS) and (rhmask), branch[.ufns];
.ufns: DISPTABLE[3],
branch[.ufnPC3];
T← (store← TSP) + 1, dbuf← SmallHi, branch[.ufnpsh1];
T← (store← TSP) + 1, dbuf← SmallHi, branch[.ufnpsh2];
.ufnpsh1:
LTEMP1← RSH[LTEMP1, 10];* Only an "alpha" byte
.ufnpsh2:
TSP← (store← T) + 1, dbuf← LTEMP1;* Push the opcode databytes
.ufnPC3:
LTEMP0← (LTEMP0) - (PCX’), call[FIXLEFT];
memBase← StackBR, branch[.FNCALL2];
*--------------------------------------------------------------------
* ufnPC: GLOBAL,
*--------------------------------------------------------------------
* CallUFN macro just turns into "SaveLink← Link, Call[ufnPC]"
ufnPC: GLOBAL,
T← A0, RBase← RBase[LTEMP0];
*May come here from totally random places, so do a little cleanup
:if[StackEmpty!];
T← StackEmpty;
* otherwise, T← A0 handled it
:endif;
StkP← T, Branch[opUFN]; * Resets the hardware stack
*--------------------------------------------------------------------
DOCALLPUNT:GLOBAL,* Called from unbox, etc.
*--------------------------------------------------------------------
* Enter with DEFLO the atom index of fnname to call
* NARGS has number of arguments to pass
* Flush out Id, recompute up LEFT
T← Id, call[FIXLEFT];
T← Id, memBase← StackBR, branch[.FNCALL1];
*--------------------------------------------------------------------
* RETURN
*--------------------------------------------------------------------
KnowRBase[LTEMP0];
top level;
InsSet[LispInsSet, 1];
opRETURN:
T← (fetch← TSP) - 1, FlipMemBase;
LTEMP0← Md, fetch← T, T← (FXBACK[ALINK]);
LTEMP1← Md, T← (PVAR) - T;
fetch← T, LTEMP3← (rhmask);* get alink field
LTEMP2← Md;
branch[.nquick, R odd], LTEMP2, T← (LTEMP2) - (FXBACK[IVAR]);
T← (fetch← T) + (FXDIF[DEFLO, IVAR]);
Q← IVAR, IVAR← Md, T← (fetch← T) + 1;* new IVAR
DEFLO← Md, T← (fetch← T) + (FXDIF[PC, DEFHI]);
T← Md, PVAR← (fetch← T) + (FXDIF[PVAR, PC]);
T← T and (LTEMP3), memBase← ifuBR;* new PVAR
BrLo← DEFLO;
:if[FNStats];
BrHi← T, branch[.retstat, R>=0], FnStatsPtr;
:else;
BrHi← T;
:endif;
T← ESP, PCF← Md;
.finishret:
LEFT← T - Q, memBase← StackBR;
T← (store← Q) + 1, dbuf← LTEMP0;
TSP← (store← T) + 1, dbuf← LTEMP1;
LEFT← (LEFT) rsh 1;
LEFT← (LEFT) - (add[LeftOffset!, 1]c), NextOpCode;
:if[FNStats];
.retstat:
DEFHI← T; PCF← Md, call[.storeretstat];* finish this operation
T← ESP, branch[.finishret];
:endif;
IFUpause[20,1,StackM2BR,0,opReturn,noNData, 0, 0];
*--------------------------------------------------------------------
* NQUICK cases of return
*--------------------------------------------------------------------
m[HardReturn, CallUFN];
.nquick:
T← (PVAR) - (FXBACK[ALINK]);
T← (fetch← T) + (FXDIF[CLINK, ALINK]);
LTEMP2← Md, T← (fetch← T) + (FXDIF[BLINK, CLINK]);
pd← (LTEMP2) - (Md) - 1, branch[.+2, R odd];
UCodeCheck[BadFrame];
branch[.+2, alu=0], LTEMP2← (LTEMP2) - 1;
HardReturn;* alink#clink
* LTEMP2 is returnee
T← (LTEMP2) - (FXBACK[FLAGS]);
fetch← T;* flagword
T← Md;
:if[Debugging];
LTEMP3← T and (StackMask);
pd← (LTEMP3) xor (FxtnBlock);
branch[.+2, alu=0];
uCodeCheck[BadFrame];
:endif;
pd← T and (rhmask);
branch[.+2, alu=0], T← (LTEMP2) - (FXBACK[NEXT]);
HardReturn;* usecnt of returnee # 0
fetch← T, T← FreeStackBlock;
LTEMP3← fetch← Md;* LTEMP3 points to returnee’s next
pd← T xor (Md);* T ← flags
branch[.+2, alu#0], T← IVAR;
branch[DORETURN];
* check for contiguous BF
pd← T xor (LTEMP3);* is IVAR=returnee’s next?
branch[.+2, alu=0], T← (PVAR) - (FXBACK[BLINK]);
HardReturn;
fetch← T;
T← Md;
fetch← T;
T← Md;
pd← T and (rhmask);
DblBranch[DORETURN, DOHARDRETURN, alu=0];
DOHARDRETURN:
HardReturn;
DORETURN:* do return to LTEMP2
T← (PVAR) - (FXBACK[BFLAGS]);
fetch← T, T← add[BfResidual!, rhmask!]c;
pd← T and Md;
branch[.freefx, alu=0], T← IVAR;
:if[Debugging];
.checkfreebf:
T← (PVAR) - (FXBACK[ALINK]);
fetch← T;
LTEMP3← Md;
branch[.+2, R odd], LTEMP3;
UCodeCheck[ShouldBeSlowFrame];
T← (PVAR) - (FXBACK[BLINK]);
:else;
.checkfreebf:
T← (PVAR) - (FXBACK[BLINK]);
:endif;
fetch← T, T← (rhmask);
LTEMP3← fetch← Md;* get bf flags
LTEMP4← Md, pd← T and Md;
branch[.nqnz, alu#0], T← (LTEMP3) + (2c);
:if[Debugging];
T← (LTEMP3) + 1;
T← (fetch← T) + 1;
pd← (IVAR) - (Md);
branch[.+2, alu=0];
uCodeCheck[IVARWRONG];
:endif;
T← T - (IVAR);
IVAR← (store← IVAR) + 1, dbuf← FreeStackBlock;
store← IVAR, dbuf← T, branch[.clresid];
.nqnz:* leave BF alone, decrement use count
T← (LTEMP4) - 1;
store← LTEMP3, dbuf← T;
.clresid:
T← (PVAR) - (FXBACK[BFLAGS]);
:if[Debugging];
fetch← T;
LTEMP3← Md;
pd←(LTEMP3) and (BFResidual);
branch[.+2, alu#0];
uCodeCheck[StackBad];
nop;
:endif;
.freefx:* make from T to ESP into a free block
ESP← (ESP) - T;
T← (store← T) + 1, dbuf← FreeStackBlock;
store← T, dbuf← ESP;
PVAR← LTEMP2;
*--------------------------------------------------------------------
RTN2:* return to frame at PVAR with LTEMP0,,LTEMP1
*--------------------------------------------------------------------
memBase← StackBR;
:if[Debugging];
T← (PVAR) - (FXBACK[FLAGS]);
fetch← T;
T← Md;
T← T and (StackMask);
pd← T xor (FxtnBlock);
branch[.+2, alu=0];
uCodeCheck[BadFrame];
:endif;
T← (PVAR) - (FXBACK[IVAR]);
T← (fetch← T) + (FXDIF[NEXT,IVAR]);
IVAR← Md, fetch← T;
ESP← Md;
TSP← Md, fetch← Md;
.extend:
ESP← (fetch← ESP) + 1;
T← Md;
pd← T xor (FreeStackBlock);
branch[.+2, alu#0], T← ESP← (fetch← ESP) - 1;
ESP← (ESP) + (Md), branch[.extend];
T← (T - (TSP)) rsh 1;
branch[.+2, carry], LEFT← T - (LeftOffset);
uCodeCheck[noStackAtPunt];
T← (PVAR) - (FXBACK[FLAGS]);
fetch← T;
LTEMP2← Md;
pd← (LTEMP2) and (FXInCall);
branch[.retcall, alu#0], pd← (LTEMP2) and (FXNoPushReturn);
branch[.nopush, alu#0], Q← TSP;
T← (store← Q) + 1, dbuf← LTEMP0;
TSP← (store← T) + 1, dbuf← LTEMP1;
branch[.retfe2, R>=0], Left← (Left) - 1;
uCodeCheck[NoStackAtPunt];
.nopush:
LTEMP2← (LTEMP2) and not (FXNoPushReturn);
store← T, dbuf← LTEMP2;* turn off no pushbit
.retfe2:
T← (PVAR) - (FXBACK[IVAR]);
T← (fetch← T) + (FXDIF[DEFLO, IVAR]);
IVAR← Md, T← (fetch← T) + 1;
DEFLO← Md, T← (fetch← T) + (FXDIF[PC, DEFHI]);
DEFHI← Md, fetch← T, T← (rhmask);
DEFHI← (DEFHI) and T, memBase← ifuBR;
BrHi← DEFHI;
BrLo← DEFLO;
PCF← Md;
:if[FNStats];
branch[.+2, R<0], FnStatsPtr;
call[.storeretstat];
NextOpCode;
:else;
nop;
NextOpCode;
:endif;
.retcall:
LTEMP2← (LTEMP2) and not (FXInCall);
store← T, dbuf← LTEMP2;
T← (TSP) - 1;
T← (fetch← T) - 1;
DEFLO← Md, T← (fetch← T) - 1;
DEFHI← Md, T← (fetch← T) - 1;
NARGS← Md; fetch← T;
:if[Debugging];
pd← DEFHI;
branch[.+2, alu=0], LTEMP0← Md;
uCodeCheck[BadRetCall];
pd← (LTEMP0) xor (SmallHi);
branch[.+2, alu=0];
uCodeCheck[BadRetCall];
:endif;
TSP← T, branch[.ATOMICFN];