*-----------------------------------------------------------
Title[DMesaRefCount.mc...September 6, 1983  11:08 AM..Taft];
*-----------------------------------------------------------
** PILOT ONLY version
** PATCHED to permit coexistence with the new Cedar 5.0 reference-counting microcode.
*-----------------------------------------------------------
   top level;

*-----------------------------------------------------------
* ALTERCOUNT[rcv, ref] RETURNS nothing
*-----------------------------------------------------------

ALTERCOUNT: MiscTable[61],    * AlterCount
   rbase← rbase[rcv], Stack&-3;
   residue← T AND (77C);
   T← (Stack&+1), membase← gcMapPiRce;
    branch[acOK, R even], Q← Stack&-2;		* check for refLo being ODD
    pd← T XOR (onStackBit);
    branch[.+2, alu=0], T← 2C;
     branch[cats];		* ref ODD and not setting onStack
    IFUNext0;		* ref ODD and doing onStack => do nothing
acOK: rcv ← T AND (refCtMask);
   onStack← T AND (onStackBit);
   T← (B← Q) rsh 1;
   probe← (residue) XOR T;
   oofNum ← T - T, Call[HTFind];
   IFUNext0;

*-----------------------------------------------------------
* CREATEREF[npr, ref] RETURNS nothing or calls Catastrophe
*-----------------------------------------------------------
CREATEREF: MiscTable[67],    * CreateRef
   rbase← rbase[rcv], Stack&-3;
   Q← (Stack&+2);
   T← (deleteRefCt);
   rcv← T - (Q);
   onStack← onStackBit;
   call[MapRefPiRes];
    branch[crf2, R<0], probe;		* branch if gc is stopped
   oofNum ← 1C;
   Call[HTFind];   * returns stored entry in T
   T← T AND (refCtMask), Stack&-1;		* point to npr
   T← T + (Stack);		* RefCt + npr
   pd← T XOR (rcFinalizeShifted);	* should have RefCt+npr = rcFinalize
    branch[.+2, alu=0], T← 3C;
    branch[cats];	* entry already in table with RefCt#Absent
   Stack&-1, IFUNext0;

      knowrbase[rcv];
crf2:  pd← gcProcNum;
    branch[.+2, alu#0];	* skip if T&S not running
    IFUNext0, Stack&-2;		* ref was NIL or gcStopped => FALSE
    T← 2C, branch[OpcodeTrap];

*-----------------------------------------------------------
OldWCLB: * IFUR[WCLB, 2, LPtr];	* Write counted long byte
**** This is now reached conditionally from ASSIGNREF in the new RC microcode ****
** ASSIGNREF[refNew, ptrRef]  => RETURNS nothing
* (<[stack[top],,stack[top-1]> + alpha)↑ ← <stack[top-2],,stack[top-3]>
** implementsAlterCount[refOld, DeleteRef], ptrRef↑ ← refNew, then AlterCount[refNew, AddRef]
*-----------------------------------------------------------
	T← ID, Stack&-1, Branch[arm1];
:IfMEP;
	T← ID, Stack&-1← MD, Branch[arm1];
	T← ID, Branch[arm1];
:EndIf;

arm1:  call[LPtrfromStackT];      * load LPtr from Stack + T
      knowrbase[rcv];
** StkP points to refNewLo
		Stack&+3;
      branch[doAssign, R<0], Stack&-2;

** StkP points to refNewHi
** refOld is in Md,,T; see if refNew (StkP,,StkP-1) = refOld
    pd← (Stack&-1) XOR Md;   * compare hi parts
     branch[.+2, alu=0], pd← (Stack&+3) XOR T;   * compare low parts
     branch[arm1x], pd← T OR Md;
    branch[arm1x, alu#0];
     Stack&-4, IFUNext0;   * refNew = refOld => do nothing

** need to worry about possible page faults
** do DeleteRef on refOld (in Md,,T(probe))
** then set the hi bit of ptrRef (at Top of Stack) as a flag
** if the AddRef on refNew page faults, we won't do another DeleteRef

arm1x: branch[arm2, R>=0], T← gcStateMask;
   pd← gcProcnum;		* gcStopped, check if TandS running
   branch[armx, alu#0];
   branch[arm2x], Stack← (Stack) OR (100000C);

arm2: onStack← T AND (onStackBit), T← Md;
   T← residue← T AND (77C);
   pd← (probe) OR T;
     branch[.+2, alu#0], probe← (probe) rsh 1;	* refOld=NIL
     branch[arm2x], Stack← (Stack) OR (100000C);
   probe← (probe) XOR T, membase← gcMapPiRce;
   oofNum← 2C;
   rcv← DeleteRefCt, call[HTFind];
** StkP points to PtrRefHi
   Stack← (Stack) OR (100000C);	* set hi bit of ptrRefHi as flag

arm2x: Stack&-2;		* point to refNewHi

doAssign: membase← LPtr, oofNum← T- T - 1;
   store← 1s, dbuf← Stack&-1;
   store← 0s, dbuf← (Stack&+1);		* do assignment

   onStack← onStackBit;     		* StkP points to refNewHi
   b← Md, call[MapRefPiRes];		* make sure assignment completed
   rcv← AddRefCt, call[HTFind]; 	* returns pointing to refNewLo
   b← Md, Stack&-1, IFUNext0;

armx:  T← 2C, branch[OpcodeTrap]; * gcStopped, TandS running
   
*-----------------------------------------------------------
* LPtrfromStackT
*-----------------------------------------------------------
     subroutine;    * T has offset to be added to ptrRefLo
LPtrfromStackT:
   T← T + (Stack&+1), rbase← rbase[rcv];
   BrLo← T, T← Stack&-3, branch[.+2, carry'];
     T← T + 1;     * carry into hi part of address
   BrHi← T;
   fetch← 0s;
   fetch← 1s, T← Md; 
   store← 0s, probe← dbuf← T;
   store← 1s, dbuf← Md, return;  * leave value in Md,,T(probe)
     top level;

*-----------------------------------------------------------
* MapRefPiRes
 * StkP points to refHi, sets probe and residue, masks onStack with gcReclaimState
*-----------------------------------------------------------
    subroutine;
MapRefPiRes:
   branch[.+3, R>=0], T← gcStateMask;
   Stkp-1;			* to match later Stack&-1
     return, probe← 100000C;    * gc is turned off if gcStateMask<0
   onStack← (onStack) AND T;
   T← (Stack&-1) and (77C);   * refHi masked to 6 bits
   pd← (Stack) OR (Q← T);
    branch[.+2, alu#0], T← (Stack) rsh 1;  * branch if ref#NIL
   return, probe← 100000C;    * ref was NIL

** Q has hi 6 bits of ref (residue -- assumes 22-bit addresses)
** probe← ((refLo rsh 1) XOR residue)  *which is 15 bits

   probe← T XOR Q;
   residue← Q, return, membase← gcMapPiRce;

*-----------------------------------------------------------
* HTFind
 * rcv, onStack, oofNum are set
*-----------------------------------------------------------
** an entry in the main table is laid out as:
**  eType[0..0], refCt[1..7], onStack[8..8], residue[9..15]
** if eType = 0, then this is a normal entry
** if eType = 1, then entry is an index into the overflow table

HTFind: branch[.+2, R>=0], probe;
** if probe<0 (100000C) means gcStopped or ref=NIL => don't do anything
      return;
    fetch← probe;
    T← (rcv) + (rcv);
    rTemp0← T;

** check for overflow entry FIRST
   T← entry← Md;
htfind1:  branch[notEmpty, R>=0], T← ResidueField[entry];
   branch[overflow, R even], entry;	* empty entry is odd & overflow
   pd← oofNum;
    branch[.+2, alu<0], T← (residue) + (rcAbsentShifted);
   T← T OR (onStack);  * don't set onStack if AddRef & new entry
   rcv← T + (rcv);
   T← (rcv) AND (nrceMask);
   store← probe, dbuf← (Q← T);		* T is used by CREATEREF
   T← HTCCrLo;

**  keep track of HTCell increments & decrements
**  Q has entry to return, T points to counter to increment
HTCellAcct:
   membase← gcStateBR;
   fetch← T;
   gctemp← (Md) + 1;
   T← (store← T) + 1, dbuf← gctemp, branch[htc1, Carry'];
    fetch← T;
    gctemp← (Md) + 1;
    store← T, dbuf← gctemp;
 htc1:  T← Q;
**  check if rcFinalizeCount increased
 rcCheck: rcv← RefCtField[T];
   pd← (rcv) XOR (rcFinalize);
    branch[.+2, alu#0], Q← T;		* most code doesn't go thru HTCellAcct
   rcFnzCount← (rcFnzCount) + 1;		* new=rcFinalize

**  keep track of RefCt increments, decrements or no changes
RefCtAcct: Q← T;		* some code doesn't go thru rcCheck
    rbase← rbase[rTemp0];
    branch[doDec, R<0], pd← rTemp0, membase← gcStateBR;
    branch[doZero, alu=0], T← ACIncLo;
rfct0:  fetch← T;
   rTemp1← (Md) + 1;
   T← (store← T) + 1, dbuf← rTemp1, branch[rfct1, Carry'];
   fetch← T;
   rTemp1← (Md) + 1;
   store← T, dbuf← rTemp1;
rfct1:  rbase← rbase[rcv], T← Q, return;

doDec:
   branch[rfct0], T← ACDecLo;
doZero:
   branch[rfct0], T← ACZeroLo;

		knowrbase[rcv];
HTCellDec: T← reclaimedRefDelta;		* from ReclaimedRef
    rTemp0← T;
    T← HTCDelLo, branch[HTCellAcct];
RefCtDec: T← reclaimedRefDelta;		* from ReclaimedRef
    rTemp0← T, branch[htc1];
*-----------------------------------------------------------
    knowrbase[rcv];
**   T← ResidueField[entry];
notEmpty:
   pd← T XOR (residue);
    branch[noMatch, alu#0], T← RefCtField[entry];
** case rce.res = residue
   pd← T XOR (rcFinalize);
    branch[.+3, alu#0], pd← T XOR (lastRefCt);
     rcFnzCount← (rcFnzCount) - 1;		* old=rcFinalize
     pd← oofNum, branch[.+3];
    branch[.+2, alu#0], pd← oofNum;
     Q← entry, branch[RefCtAcct];		* don't need to check FnzCount

    branch[ne1, alu>=0], T← (rcv) + Md;  * entry still in Md

** AddRef case, turn off stackBit if refCt>rcFinalize (refCt>=rcAbsent)
   residue← RefCtField[T];
   pd← (residue) - (rcAbsent);
    branch[ne2, alu<0], T← T OR (onStack);
   T ← T AND (undoStackBit), branch[ne2];

 ne1: T← T OR (onStack);
 ne2: gcTemp← RefCtStkField[T];
   pd← (gcTemp) XOR (becameEmpty);
    branch[.+2, alu=0], T← T AND (nrceMask);
   store← probe, dbuf← (Q← T), branch[rcCheck];		* found a match
    store← probe, T← dbuf← rceEmpty;
   Q← T;
   T← HTCDelLo,  branch[HTCellAcct];		* don't need to check FnzCount
    
*-----------------------------------------------------------
** probe already contained an entry, so must make an overflow
*** entry with two entries on it
noMatch:
   membase← gcStateBR;
   T← (residue) + (rcAbsentShifted);
   gLink← Link;
      TOP LEVEL;
   call[createOi], rcv← T + (rcv);

** returns with T having addr of even word in overflow table
** rcv is the new entry, entry is the one found in MapPirce
   
   pd← oofNum;
    branch[.+2, alu<0], Q← onStack;
    rcv← (rcv) OR Q;    * don't set onStack if AddRefC
    rcv← (rcv) AND (nrceMask);
   T← (store← T) + 1, dbuf← rcv;	* new entry
   T← (store← T) - 1, dbuf← entry;	* entry from MapPiRce

   membase← gcMapPiRce;
   store← probe, dbuf← T;  ** update MapPiRce
   link← gLink;
     SUBROUTINE;
   T← rcv, branch[rcCheck];		** no match found

*-----------------------------------------------------------
* need to look at an overflow chain

overflow:
   membase← gcStateBR, oiPrev0← T - T;
   oiPrev1← T - T;
   gLink← Link;
   	rme[oiCurrent, entry];

ofLoop:
   oiCurrent← (fetch← oiCurrent) + 1;
   gcTemp← Md;
    branch[.+2, R>=0], T← ResidueField[gcTemp];
     branch[cats], T← A0;	* malformed overflow chain

   pd← T XOR (residue);

 ofL0: branch[.+2, alu=0], T← RefCtField[gcTemp];
     branch[ofNoMatch];
 * p0e.rce.res = residue
   pd← T XOR (rcFinalize);
    branch[.+3, alu#0], pd← T XOR (lastRefCt);
     rcFnzCount← (rcFnzCount) - 1;		* old=rcFinalize
     T← (rcv) + Md, branch[.+3];
    branch[.+2, alu#0], T← (rcv) + Md;
     T← gcTemp, branch[RefCtAcct];		* found match, but didn't change it
   T← T OR (onStack);
   gcTemp← T← T AND (nrceMask);

   pd← oofNum;
    branch[ofLoop1, alu>=0], T← RefCtField[gcTemp];     * refCt
   pd← T - (rcAbsent);
    branch[of1, alu<0], T← RefCtStkField[gcTemp];
   gcTemp← T← (gcTemp) AND (undoStackBit);   *AddRef case, refCt>=rcAbsent

 ofLoop1: T← RefCtStkField[gcTemp];
 of1: pd← T XOR (becameEmpty);
    branch[of2, alu=0], T← (oiCurrent) - 1;
* found match, entry did not become vacant
   Link← glink;
      SUBROUTINE;
   store← T, T← dbuf← gcTemp, branch[rcCheck];

 * entry just became empty - take it off the list
** NOTE: entry has not been stored into, but that's OK

		TOP LEVEL;
 of2: T← (fetch← oiCurrent) - 1;
   call[FreeOi], gcTemp2← Md;  *oiCurrent.oe1
    branch[.+2, R<0], T← oiPrev1;
   membase← gcMapPiRce, T← probe;	* oiPrev = 0
   Link← glink;
      SUBROUTINE;
   store← T, dbuf← gcTemp2;
   T← rceEmpty, branch[RefCtAcct];		* don't check FnzCount

		TOP LEVEL;
* current entry doesn't match, see if second entry is end of chain
ofNoMatch:
   fetch← oiCurrent;
   gcTemp2← Md;
    branch[ofMidChain, R<0], T← ResidueField[gcTemp2];
   pd← T XOR (residue);
    branch[endofChain, alu#0], T← RefCtField[gcTemp2];
   pd← T XOR (rcFinalize);
    branch[.+3, alu#0], pd← T XOR (lastRefCt);
     rcFnzCount← (rcFnzCount) - 1;		* old=rcFinalize
     T← rcv, branch[matchAtEnd];
    branch[matchAtEnd, alu#0], T← rcv;
   Link← gLink;
     SUBROUTINE;
   T← gcTemp2, branch[RefCtAcct];

     TOP LEVEL;
ofMidChain: oiPrev0← oiPrev1;
   oiPrev1← oiCurrent;
   oiCurrent← Md, branch[ofLoop];

matchAtEnd: T← (gcTemp2) + T;
   T← T AND (nrceMask);
   gcTemp2← T OR (onStack);
   pd← oofNum;
    branch[mae0, alu>=0], T← RefCtStkField[gcTemp2];
   T← RefCtField[gcTemp2];
   pd← T - (rcFinalize1);
   branch[.+2, alu>=0];
    gctemp2← (gctemp2) AND (undoStackBit);
   T← RefCtStkField[gcTemp2];
mae0: pd← T XOR (becameEmpty);
    branch[endBecameEmpty, alu=0], T← oiCurrent;
   Link← glink;
      SUBROUTINE;
   store← T, T← dbuf← gcTemp2, branch[rcCheck];

     TOP LEVEL;
endBecameEmpty:
   T← (oiCurrent) - 1;
   fetch← T;
   call[FreeOi], gcTemp2← Md;			* OiCurrent.rce
    branch[.+2, R<0], T← oiPrev1;
    membase← gcmapPiRce, T← probe;
mae1: Link← glink;
      SUBROUTINE;
   store← T, dbuf← gcTemp2;
   T← rceEmpty, branch[RefCtAcct];		* don't check FnzCount

     TOP LEVEL;

** end of overflow chain without a match
* create a new overflow entry and put it at the head of the chain
     TOP LEVEL;
 endofChain:
   T← (residue) + (rcAbsentShifted);
    branch[.+2, R<0], oofNum;
    T← T OR (onStack);		* don't set onStack if AddRef
   call[createOi], rcv← (rcv) + T;
   rcv← (rcv) AND (nrceMask);
   membase← gcMapPiRce;
   fetch← probe;
   store← probe, dbuf← T, flipmembase;
   T← T + 1, Link← glink;
      SUBROUTINE;
   T← (store← T) - 1, dbuf← Md;		* store link first
   store← T, T← dbuf← rcv, branch[rcCheck];

*-----------------------------------------------------------
* createOi returns the overflow index in T
** expects membase← GCState, rbase← rbase[rcv]
*-----------------------------------------------------------
*  theshhold = (IF (GCState.reclaimState = gcRunning) AND
*    (Process.GetCurrent[] = GCState.collector) THEN don't check ELSE 0);
   subroutine;
 createOi:
   pd← (gcStateMask) AND (gcRunningC),   global;
    branch[co1, alu=0], T← (nOiFree) - 1;
  rbase← rbase[RTemp0], T← gcProcNum;
  pd← (CurrentPSB) xor T, rbase← rbase[gcTemp2];
    branch[co1x, alu#0], T← (nOiFree) - 1;
   nOiFree← T, branch[co2x];		* collector needs an overflow entry

co1: dblbranch[outofOverflowTab, co2, alu<0];
co1x: branch[outofOverflowTab, alu<0];
** for debugging running out of overflow table
*    pd← (oofNum) xor (3C);
*     branch[.+2, alu#0];   * DeleteRef case of ASSIGNREF only
*     branch[outofOverflowTab];
*    nop;
** for debugging running out of overflow table

co2: nOiFree← T;   * update nOiFree
co2x:  T← fetch← oiFreeList, branch[coError, R>=0], oiFreeList;
   oiFreeList← Md, Q← T;
   T← OTCCrLo;
CellAcct:
   fetch← T;			* membase is gcStateBR
   rbase← rbase[rTemp1];
   rTemp1← (Md) + 1;
   T← (store← T) + 1, dbuf← rTemp1, branch[otc1, alu#0];
   Fetch← T;
   rTemp1← (Md) + 1;
   store← T, dbuf← rTemp1;
 otc1: T← Q, rbase← rbase[rcv], return;

RstkCellAcct: T← HTCDelLo, branch[CellAcct];

    top level;
coError:  branch[cats], T← 1C;     * OiError, next is not in overflowtable

*-----------------------------------------------------------
* FreeOi - put the entry pointed to by T back on the
*  freelist of Oi's (linked thru even words) - T is even
*-----------------------------------------------------------
  subroutine;
FreeOi:
   store← T, dbuf← oiFreeList;
   oiFreeList← T;
   nOiFree← (nOiFree) + 1;   * update count of free entries
   T← OTCDelLo, branch[CellAcct];

*-----------------------------------------------------------
   top level;
* HTFind leaves StkP pointing to second (hi) word of ref

** SD[171C] => RTStartImpl.ClobberedOverflowTable[] if oofNum = 4 or OiError

outofOverflowTab:
    branch[OpcodeTrap], T← 1C;

    top level;
cats: Q← T;
  call[rrx];
  rbase← rbase[RTemp0], b← Md;
  T← SDCatastrophe;
  TrapParam← Q, branch[SavePCAndTrap];
*-----------------------------------------------------------

RcFinalizeCount:	rbase← rbase[rcv],	MiscTable[64];
  T← rcFnzCount;
  Stack← T, IFUNext0;

*-----------------------------------------------------------

*Misc70:	T← A0, branch[OpcodeTrap],	MiscTable[70];

*-----------------------------------------------------------

ReadRegs:	call[rrx],	MiscTable[66];
  Stack← T - T - 1, IFUNext0;

  SUBROUTINE;

rrx:  rbase← rbase[rcv];
  membase← gcStateBr;
  T← dumpTableOffset;		** dumpTable part of GCstate
  T← (store← T) + 1, dbuf← rcv;
  T← (store← T) + 1, dbuf← residue;
  T← (store← T) + 1, dbuf← probe;
  T← (store← T) + 1, dbuf← entry;
  T← (store← T) + 1, dbuf← onStack;
  T← (store← T) + 1, dbuf← oiPrev0;
  T← (store← T) + 1, dbuf← oiPrev1;
  T← (store← T) + 1, dbuf← gcTemp;
  T← (store← T) + 1, dbuf← gcTemp2;
  T← (store← T) + 1, dbuf← oofNum;
  T← (store← T) + 1, dbuf← oiFreeList;
  T← (store← T) + 1, dbuf← nOiFree;
  T← (store← T) + 1, dbuf← gcStateMask;
  T← (store← T) + 1, dbuf← gcProcNum;
  T← (store← T) + 1, dbuf← rcFnzCount, return;

*-----------------------------------------------------------
   top level;

*-----------------------------------------------------------
** debugging
*-----------------------------------------------------------
*DUMPINDEX[probe] RETURNS [count]
*-----------------------------------------------------------
* arrive with rbase[rTemp0], T has probe
	knowrbase[rTemp0];
DUMPINDEX: MiscTable[70],    * Dump a probe index
   membase← gcMapPiRce;
   fetch← T, Stack&-1;		* reset to top of Stack
   rTemp0← dumpTableOffset;    * count
   T← rTemp1← Md;
   branch[storeLast, R>=0], rTemp1, membase← GCStateBR;
   branch[diLoop, R EVEN], rTemp1;	* branch if overflow entry
   Stack← A0, IFUNext0;		* no entries
*---------------------------- normal entry
storeLast:
	rTemp0← (store← rTemp0) + 1, dbuf← T;
sL1:	T← (rTemp0) - (dumpTableOffset);
	Stack← T, IFUNext0;		* one entry
*---------------------------- must look at an overflow chain of entries
diLoop:  T← (fetch← T) + 1;    * fetch first part of overflow entry
dL1:	T← Md, fetch← T;
	rTemp0← (store← rTemp0) + 1, dbuf← T;
	T← pd← Md;
   branch[.+2, alu>=0];		* end of chain
   T← (fetch← T) + 1, branch[dL1];
   rTemp0← (store← rTemp0) + 1, dbuf← T, branch[sL1];