{
file: GcRef.mc
last edit:     29-Feb-84 10:42:04 by cal, added uGcZero
last edit:     15-Feb-84 12:03:38 by cal, added RefCount Exit
last edit:     25-Aug-83 14:30:28 by cal, added non-lisp ptr check{virtual range}
last edit:     5-Aug-83 15:33:49 by charnley
put into system: 28-Jun-83 11:12:18
created:  2-Jun-83 14:36:05 by charnley
}

SetTask[0];

{*******************************************************************
	GCREF	
*******************************************************************}

{	alpha contains code: 0 addRef, 1 delRef, 2 stkRef
	TOSH contains high address bits
	TOS contains low address bits
	replaces TOSH,,TOS with NIL except in the case that  the new value
	has stk = 0, and refcnt = 0, in which case stack left alone
}

GcRef:	opcode[25'b],
	TT ← RShift1 0, SE ← 1,	c1; {set sign bit of Q}
	Q ← TT + ibNA, L1 ← L1.NoFixes,	c2;
	Rx ← TOSH and 0FF, L2 ← L2.gcref,	c3;

	TT ← TOS, CALL[GcLookup],	c1;

{*******************************************************************
	GCLOOKUP SUBROUTINE	
*******************************************************************}

{	Q contains code: 0 addRef, 1 delRef, 2 stkRef {sign bit = 1 if opcode}
	Rx contains high address bits {will be put into uGcLhi}
	  if Rx = 0, then treat as atom
	TT has low address bits {will be put in uGcLlo}
	uGcLov returns non-zero if overflow entry added {for non-opcode}
	uGcZero returns non-zero if entry created {for non-opcode}
	TT returns 0 in the case that  the new value
	has stk = 0, and refcnt = 0
	L2 contains caller
}

{
	The address of a type table word is:
	   PageTableBase + Top 15 address bits

	The format of a type table word is:
	   bit 0 -- Atom
	   bit 1 -- Don't RefCnt, goto ufn

	The address of a hash table entry is:
	   HashTableBase + ( Low 16 address bits ) / 2

	The format of a hash table entry is:
	   bits
	   0..5    -- Count {63 = max count, if count is one
	                     entry is not in hash table}
	   6       -- Stack Ref bit
	   7..14   -- eight high address bits
	   15      -- Collision bit, goto ufn
}
GcLookup:
	uGcLlo ← TT,	c2;
	TT ← TT and ~0FF,	c3;

	uGcLhi ← Rx, ZeroBr,	c1;
	rhRx ← crhHashTable, BRANCH[$, GcLHighZero],	c2;
	rhTT ← crhTypeTable, TT ← TT or Rx,	c3;
	
	Xbus ← Rx LRot12, XDisp,	c1;
	TT ← TT LRot8, DISP4[GcLTest, 3],	c2;
	TT ← RShift1 TT, SE ← 1,{or 80 with page},	c3, at[03, 10, GcLTest];

	MAR ← [rhTT, TT + 0],	c1;{read Type table}
	Rx ← uGcLlo,	c2;
	TT{Probe} ← MD,	c3;

	TT ← LShift1 TT, NegBr,{test sign bit}	c1;
	Ybus ← TT, NegBr, BRANCH[$, GcLatom],	c2;{test 4000 bit}
	Rx ← RShift1 Rx, SE ← 0, BRANCH[$, GcLpunt1],	c3;

	MAR ← [rhRx, Rx + 0],	c1;{read hash table}
	uGcLTem ← Rx,	c2;{save HT addr}
	TT{Entry} ← MD,	c3;

	Ybus ← TT and 1, NZeroBr,	c1;{test coll bit}
	Ybus ← TT, ZeroBr, BRANCH[$, GcLcoll],	c2;{test empty}
	Rx ← uGcLhi, BRANCH[$, GcLempty],	c3;

	Rx ← LShift1 Rx, SE ← 0,	c1;
	Rx ← RShift1 Rx xor TT, SE ← 0,	c2;
	Rx ← Rx - 1, PgCarryBr,	c3;{compare hi addr}

	Rx ← 8, BRANCH[$, GcLdifptr],	c1;{sub has PgCarry compl}
	Rx ← Rx LRot8,	c2;{Rx ← 0800}
	Ybus ← TT + Rx, CarryBr,	c3;{cnt = 62 or 63?}

GcLSel:	Ybus ← Q, YDisp, BRANCH[$, GcLcntovf],	c1;
	Rx ← RShift1 Rx, SE ← 0, DISP2[GcLdisp],	c2;{Rx ← 0400}
	Rx ← RShift1 Rx, SE ← 0,{stkRef}	c3,at[2,4,GcLdisp];{Rx ← 0200}

	Q ← TT or Rx,	c1;
	Noop, GOTO[GcLpw],	c2;

	Q ← TT + Rx, GOTO[GcLcom], {addRef}	c3,at[0,4,GcLdisp];
	Q ← TT - Rx, GOTO[GcLcom], {delRef}	c3,at[1,4,GcLdisp];

GcLcom:	TT ← Q and ~u1FF,	c1;{TT ← cnt,,stk}
	Ybus ← TT xor Rx, ZeroBr,	c2;{TT = 1,,0 ?}
GcLpw:	Rx ← uGcLTem, BRANCH[$, GcLc1s0],	c3;{get HT addr}

	MAR ← [rhRx, Rx + 0],	c1;
	MDR ← TT ← Q,	c2;
GcLfin:	TT ← TT and ~u1FF, L2Disp, GOTO[GcLend],	c3;

	{EXCEPTIONS}

GcLc1s0:	MAR ← [rhRx, Rx + 0],	c1;
	MDR ← TT ← 0, GOTO[GcLatom],	c2;{store 0}

GcLatom:	TT ← TT xor ~TT{non-zero}, L2Disp, CANCELBR[GcLend],	c3;

GcLHighZero:	TT ← TT xor ~TT{non-zero}, L2Disp, CANCELBR[GcLend],	c3;

GcLcntovf:
	Noop, CANCELBR[GcLcoll, 3],	c2;

GcLempty:	{build a new entry with a cnt of 1}
	Rx ← uTT3FF,	c1;{Rx ← 03FF}
	uGcZero ← Rx,	c2;
	TT ← uGcLhi ,	c3;

	TT ← LShift1 TT , SE ← 0,	c1;
	TT ← TT + Rx + 1,	c2;{TT ← TT + 400}
	Rx ← LShift1 Rx + 1, SE ← 1, GOTO[GcLSel],	c3;{Rx ← 0801}


{	Entry into overflow table here	}
GcLpunt1:	Noop,	c1;
GcLdifptr:	Noop,	c2;
GcLcoll:	Rx ← Q, NegBr, CANCELBR[$],	c3;{test if opcode}

	Rx ← Rx LRot8, BRANCH[$, GcLufn],	c1;
	TT ← 0A0,	c2;
	TT ← TT LRot8	c3;{build ov table addr}

GcLfov:	MAR ← [rhTT, TT + 0],	c1;
	Noop,	c2;
	Q ← MD,	c3;

	Ybus ← Q, ZeroBr,	c1;{is ov empty?}
	uGcLov ← TT, BRANCH[GcLnext, $],	c2;{uGcLov # 0}
	Q ← uGcLhi,	c3;

	MAR ← [rhTT, TT + 0],	c1;
	MDR ← Rx or Q,	c2;
	Rx ← uGcLlo,	c3;

	MAR ← [rhTT, TT + 1],	c1;
	MDR ← Rx, LOOPHOLE[wok], CANCELBR[$, CB2],	c2;
GcLret:
	L2Disp, GOTO[GcLend],	c3;

GcLnext:	TT ← TT + 2, GOTO[GcLfov],	c3;


GcLufn:	Rx ← 25'b, GOTO[ufn3], {only occurs if GcRef opcode}	c2;

GcLend:	RET[GcLookRet],{** EXIT HERE **} 	c1;

	Ybus ← TT, ZeroBr, Xbus ← ib,	c2,at[L2.gcref,10,GcLookRet];
	PC ← PC + 1, BRANCH[$, GcRlvTOS],	c3;

	TOS ← 0,	c1;
	TOSH ← 0, IBDisp, L2 ← L2.0, GOTO[DNI.nop],	c2;

GcRlvTOS:	Noop, GOTO[IB.nop],	c1;

	Ybus ← Q, NegBr, GOTO[GcLOut],	c3, at[07, 10, GcLTest];
	Ybus ← Q, NegBr, GOTO[GcLOut],	c3, at[0B, 10, GcLTest];
	Ybus ← Q, NegBr, GOTO[GcLOut],	c3, at[0F, 10, GcLTest];

GcLOut:
	BRANCH[GcLnotop, GcLop],	c1;

GcLop:	Rx ← 25'b, GOTO[ufn3],	c2;
GcLnotop:	GOTO[GcLret],	c2;
	
	{ E N D }