*-----------------------------------------------------------
Title[DMesaReclaim.mc..August 29, 1983  4:06 PM..Taft];
*-----------------------------------------------------------
** PILOT ONLY version
** PATCHED to permit coexistence with the new Cedar 5.0 reference-counting microcode.
*-----------------------------------------------------------
   top level;

*-----------------------------------------------------------
* ReclaimedRef[ref] RETURNS ref or NIL
*-----------------------------------------------------------
ReclaimedRef: MiscTable[60];   * placement
   rbase← rbase[rcv], Stack&-1;
   call[MapRefPiRes];
    branch[.+2, r>=0], probe, membase← gcMapPiRce;
    Stack&+1, IFUNext0;		* ref = NIL, do nothing

   fetch← probe;
   entry← Md;
    branch[rrentry, R>=0], entry, T← ResidueField[entry];
    branch[rrof, R even], entry;
    Stack&+1, IFUNext0;			* not in table, return ref
rrentry: pd← T XOR (residue);
    branch[.+2, alu=0], T← RefCtField[entry];
    Stack&+1, IFUNext0;			* not in table, return ref
* found as normal entry, so do a deleteref on the entry if not pinned
   pd← T;
    branch[.+2, alu#0], pd← T XOR (lastRefCt);
    branch[cats4];		* OldRefCt = 0
    branch[.+2, alu#0], pd← T XOR (rcFinalize);
      Stack&+1← T - T, branch[rr0n];
    branch[.+2, alu#0], entry← (entry) + (reclaimedRefDelta);
    rcFnzCount← (rcFnzCount) - 1;		*RfCntOld = rcFinalize
   entry← (entry) AND (nrceMask);
   T← RefCtStkField[entry];
   pd← T XOR (becameEmpty);
    branch[rrempty, alu=0], T← entry;
rre1: store← probe, dbuf← T;
rr0: Stack&+1← T - (Q← T);
   call[RefCtDec];
rr0n: Stack← T - T;
   IFUNext0;

rrempty: store← probe, T← dbuf← rceEmpty;
   Q← T;
   call[HTCellDec];
   branch[rr0n], Stack&+1← T - T;

* found an overflow entry in MapPiRce
    knowrbase[rcv];
rrof: membase← gcStateBR, oiPrev1← T - T;
      rme[oiCurrent, entry];
rrLoop: oiCurrent← T← (fetch← oiCurrent) + 1;
   gcTemp← Md, fetch← T;
    branch[.+2, R>=0], T← ResidueField[gcTemp];
     branch[cats1];
   pd← T XOR (residue);
    branch[rr1, alu=0], gcTemp2← Md;
    branch[rr2, R<0], gcTemp2, T← ResidueField[gcTemp2];
   pd← T XOR (residue);
    branch[.+2, alu=0], T← RefCtField[gcTemp2];
    Stack&+1, IFUNext0;			* not found, return ref
   pd← T;
    branch[.+2, alu#0], pd← T XOR (lastRefCt);
     branch[cats4];		* OldRefCt = 0
    branch[.+2, alu#0], pd← T XOR (rcFinalize);
    branch[rr0n], Stack&+1← T-T;			* found, return NIL, no decrement done
    branch[.+2, alu#0], gcTemp2← (gcTemp2) + (reclaimedRefDelta);
    rcFnzCount← (rcFnzCount) - 1;		*RfCntOld = rcFinalize
   gcTemp2← (gcTemp2) AND (nrceMask);
   T← RefCtStkField[gcTemp2];
   pd← T XOR (becameEmpty);
    branch[rr0x, alu=0], T← gcTemp2;
    store← oiCurrent, dbuf← T, branch[rr0];

* second entry at end of chain became empty
rr0x: call[FreeOi], T← (oiCurrent) - 1;
    branch[.+2, R<0], T← oiPrev1;
     membase← gcMapPiRce, T← probe;
   store← T, T← dbuf← gcTemp, branch[rr0];   

* in middle of chain, continue following
rr2: oiPrev1← oiCurrent;
   oiCurrent← Md, branch[rrLoop];
   
* oiCurrent.rce.res = res
rr1: T← RefCtField[gcTemp];
    pd← T;
     branch[.+2, alu#0], pd← T XOR (lastRefCt);
     branch[cats4];		* OldRefCt = 0
    branch[.+2, alu#0], pd← T XOR (rcFinalize);
    branch[rr0n], Stack&+1← T-T;			* found, return NIL
    branch[.+2, alu#0], gcTemp← (gcTemp) + (reclaimedRefDelta);
    rcFnzCount← (rcFnzCount) - 1;		*RfCntOld = rcFinalize
   gcTemp← (gcTemp) AND (nrceMask);
   T← RefCtStkField[gcTemp];
   pd← T XOR (becameEmpty);
    branch[.+2, alu=0], T← (oiCurrent) - 1;
    store← T, T← dbuf← gcTemp, branch[rr0];
* oiCurrent.rce became empty, Md still has oiCurrent.oe1
   gcTemp← Md, branch[rr0x];
   
*-----------------------------------------------------------
* RTSETUP[flag, GCStateHi] RETURNS uVersion

* if flag<0 => full setup, refetch all of GCState Info
* if flag>=0 => fetch gcstateMask and gcProcNum, store FreeList and nOiFree
*-----------------------------------------------------------

RTSetup: MiscTable[63], Stack&-3;   * placement, make stack empty?
   T← TIOA&StkP;
   T← T AND (377C), StkP+2;	* restore two args
   T← Stack&-1, branch[rtsOK, alu=0];
   T← 1C;
   StkP← T;
** stack depth was > 2 => wrong software for this microcode
   Stack← WrongUVersion, IFUNext0;

rtsOK: membase← gcStateBR,		* T has gcStateHi
	Call[DisableNewRCMicrocode];
    rbase← rbase[gcTemp], branch[rts2, R>=0], Stack;
   gcTemp← (BrHi← T) - T;
   BrLo← gcTemp;   * BrLo← 0
   fetch← 14S;
   fetch← 0s, rcFnzCount← Md;
   fetch← 1s, oiFreeList← Md;
   fetch← 2s, nOiFree← Md;
   fetch← 3s, gcStateMask← Md;
   membase← gcMapPiRce, gcProcNum← Md;
   gcProcNum← LSH[gcProcNum, 2];	* microcode keeps procNum*4
   BrHi← T;
   T← (mapPiRceOffset);
   BrLo← T;
   Stack← UVersion, IFUNext0;
*
 rts2: T← (fetch← 2s) + 1;
   fetch← T, gcStateMask← Md;
   gcProcNum← Md;
   gcProcNum← LSH[gcProcNum, 2];	* microcode keeps procNum*4
   store← 14s, dbuf← rcFnzCount;
   store← 0s, dbuf← oiFreeList;
   store← 1S, dbuf← nOiFree, IFUNext0;	** need not return UVersion

*-----------------------------------------------------------
* ResetSTKBits[probe] RETURNS nothing
*-----------------------------------------------------------
ResetSTKBits: MiscTable[62];		** placement
  rbase← rbase[rcv], Stack&-1;
rstkLoop: membase← gcMapPiRce, Stack, branch[.+2, R>=0] ;
    Stack&-1, IFUNext0;		* done
  fetch← Stack;
  entry← Md;
   branch[rstkx, R>=0], pd← (entry) AND (emptyRefCtMask);
   branch[rstkx1, R EVEN], entry;
 rstkL1: dblbranch[rstkLoop, rstkResched, Reschedule'], Stack← (Stack) + 1;
 rstkResched: branch[MesaReschedTrap], b← Md;

*  normal entry, check for becoming absent
rstkx: branch[.+2, alu=0], T← (entry) AND (undoStackBit);
  store← Stack, dbuf← T, branch[rstkL1];
  store← Stack, dbuf← rceEmpty;
rstkAcct: membase← gcStateBR;
   call[RstkCellAcct];
  branch[rstkL1];

* overflow entry
rstkx1: membase← gcStateBr, oiPrev1← T - T;
  oiPrev0← T - T;
     rme[oiCurrent, entry];
rstk0: T← (fetch← oiCurrent) + 1;
  gcTemp← Md;			* oiCurrent.rce
   branch[.+2, R>=0], pd← (gcTemp) AND (emptyRefCtMask);
     branch[cats1];
   branch[rstk1, alu=0], T← gcTemp← (gcTemp) AND (undoStackBit);
*   oiCurrent.rce # absent
  oiCurrent← (store← oiCurrent) + 1, dbuf← T;
  fetch← oiCurrent;		* oiCurrent.oe1
  gcTemp2← Md;
   branch[rstkMidChain, R<0], pd← (gcTemp2) AND (emptyRefCtMask);

* end of the chain, oiCurrent.oe1 (gcTemp2) is a normal entry
   branch[.+2, alu=0], T← (gcTemp2) AND (undoStackBit);
   store← oiCurrent, dbuf← T, branch[rstkL1];	*oiCurrent.oe1 was not empty

* oiCurrent.oe1 => empty, move oiCurrent.rce (gcTemp) to oiPrev1 or MapPiRce
  call[FreeOi], T← (oiCurrent) - 1;
   dblbranch[rstk2, rstk2x, R<0], oiPrev1, T← oiPrev1;
 
* oiPrev1 = 0 => move gcTemp into MapPiRce
rstk2x: membase← gcMapPiRce, T← Stack;

* oiPrev # 0 => oiPrev.oe1← gcTemp
rstk2:  store← T, dbuf← gcTemp, branch[rstkL1];

rstkMidChain: oiPrev0← oiPrev1;
  oiPrev1← oiCurrent;
  oiCurrent← Md, branch[rstk0];

* oiCurrent.rce became empty, must check oiCurrent.oe1
rstk1: T← (oiCurrent) + 1;
  T← (fetch← T) - 1;
  gcTemp← Md, call[FreeOi];
   branch[rstk3, R<0], pd← (gcTemp) AND (emptyRefCtMask);
* this is the end of the overflow chain
   branch[rstk4, alu=0], T← gcTemp← (gcTemp) AND (undoStackBit);
* oiCurrent.oe1 did not become empty
   dblbranch[rstk2, rstk2x, R<0], oiPrev1, T← oiPrev1;

* entry in the middle of a chain became empty; oiCurrent has been freed
* gcTemp has the link to the next entry
rstk3: branch[rstk3x, R<0], T← oiPrev1;
* oiPrev1 = 0, => make MapPiRce point to next entry
  membase← gcMapPiRce, T← gcTemp;	* pointer to next on chain
  store← Stack, dbuf← T;
  membase← gcStateBR, branch[rstk0], oiCurrent← T;		* continue chaining

* oiPrev1 # 0, => oiPrev1.oe1← gcTemp
rstk3x: store← T, T← dbuf← gcTemp;
  oiCurrent← T, branch[rstk0];
  
** most complicated case - both entries at the end of the chain became empty
* if there was only one overflow entry, then MapPiRce← rceEmpty
* otherwise, we must look at the entry previous to the previous one (oiPrev0)

rstk4: branch[rstk5, R<0], T← (oiPrev1) - 1;
* no previous entry, make MapPiRce entry vacant
  membase← gcMapPiRce;
  store← Stack, dbuf← rceEmpty;
  branch[rstkAcct];

*  free the Oi at oiPrev1, after fetching its rce, then use oiPrev0 to decide where
** to store oiPrev1.rce
rstk5: fetch← T;
  gcTemp← Md, call[FreeOi];
  dblbranch[rstk2, rstk2x, R<0], T← oiPrev0;

*-----------------------------------------------------------
* ISPIRECLAIMABLE[pi: ProbeIndex] RETURNS[pi: ProbeIndex, npi: CARDINAL]
**  code checks for ReSchedule every time around the loop

** stores possibly reclaimable rce's in GCState.rceToReclaim and
** returns the number of rce's it stored for a particular probeIndex
**  when npi is returned as 0, the loop is finished
** an rce is a possibly reclaimable REF if rce.rc <= rcFinalize and onStack is not set
*-----------------------------------------------------------
ISPIRECLAIMABLE: MiscTable[65],    * IsPiReclaimable
   Stack&-1← A0;    * preset npi to 0 - used as counter
   rbase← rbase[rcv];	* placement
   rcv← rceReclaimOffset;
   membase← gcMapPiRce, T← pd← Stack;
* one extra fetch beyond MapPiRce is ok - that is MapOiOe
 ipLoop: fetch← T, branch[.+2, alu>=0];	* finished when T < 0
    Stack&+1, b← Md, IFUNext0;
   Stack← T;
   entry← Md;
   entry← RefCtStkField[entry], branch[isprn, R>=0];
   entry← Md;
    branch[isprof, R EVEN], entry;	* branch if overflow entry
    T← (Stack) + 1, dblbranch[ipLoop, iplResched, ReSchedule'];

 *---------------------------- normal entry
isprn: branch[ipl2, r Odd], pd← (entry) - (rcFinalize1);  * branch if onStack set
   branch[.+2, alu<0];  * skip if possibly reclaimable
     T← (Stack) + 1, dblbranch[ipLoop, iplResched, ReSchedule'];

   membase← GCStateBR, Stack&+1;
   store← rcv, dbuf← Md;   * might be reclaimable
   Stack← (Stack) + 1, b← Md, IFUNext0;
*---------------------------- check for pending interrupts
*--------- update Stack (can't before because of page faults)
  ipL2: dblbranch[ipLoop, iplResched, ReSchedule'], T← (Stack) + 1;
*---------------------------- must look at an overflow chain of entries
isprof:
   membase← GCStateBR;	   * Md has MapPiRce[pi]
   T← (fetch← entry) + 1;    * fetch rce part of overflow entry
 ispr1: T← gcTemp← Md, fetch← T;
    branch[.+2, R>=0], gcTemp← RefCtStkField[gcTemp];
     branch[cats1];
    branch[.+2, r even], pd← (gcTemp) - (rcFinalize1); 
    branch[ispr2], gcTemp← Md;   * onStack was set
   branch[ispr2, alu>=0], gcTemp← Md;
**-------------- store entry in GCState.rceToReclaim[rcv]
   rcv← (store← rcv) + 1, dbuf← T;
ispr2: branch[.+2, R>=0], gcTemp← RefCtStkField[gcTemp];
   T← (fetch← Md) + 1, branch[ispr1];	* Md has second entry, follow chain
** end of chain, check second entry (gcTemp)
    branch[ispr3, R odd], pd← (gcTemp) - (rcFinalize1);	* onStack was set
    branch[ispr3x, alu>=0], T← (rcv) - (rceReclaimOffset);
    rcv← (store← rcv) + 1, dbuf← Md, branch[ispr4];
    
**-------------- check if anything was stored in GCState.rceToReclaim
ispr3: T← (rcv) - (rceReclaimOffset);   * test if npi = 0
ispr3x: branch[ispr4x, alu#0], membase← gcMapPiRce;
 * go looking for more
    dblBranch[ipLoop, iplResched, ReSchedule'], T← (Stack) + 1;
ispr4: T← (rcv) - (rceReclaimOffset);
ispr4x: Stack+1← T, b← Md, IFUNext0;    ** did find something
*---------------------------- allow other processes to run
iplResched:  b← Md, rbase← rbase[rtemp0];
  branch[MesaReschedTrap];

*-------------------------------------------------------- 
cats1: branch[cats], T← 1C;
cats4: branch[cats], T← 4C;